题目描述
有三个没有刻度的杯子,容量分别为 a 升、b 升与 c 升。一开始,只有容量为 c 的杯子中灌满了水,另外两个杯子是空的。
小爱可以将水从一个杯子倒去另一个杯子,倒水过程直到原杯子变空或新杯子变满才会停止。水只能在杯子间转移,不会凭空增加或减少。
小爱希望通过倒水,能在某个杯子中,恰好出现一升水。若不可行,则在某个杯子中尽量出现较少的水(不为空),请输出最少能有多少水可以出现在某个杯子里,并输出最少需要多少步才能达到这一目的。
输入格式
第一行:三个整数 a,b 与 c
输出格式
第一行:单个整数表示某个杯子中能留下的最少液体数量。
第二行:单个整数表示达到该目的时,倒水操作的最少步骤。
数据范围
1≤a≤b≤c≤5000
样例
输入:
2 3 5
输出:
1
2
说明:
5–>3
3–>2
3这个杯子里剩下1升
分析
BFS+模拟。
我们直接模拟倒水的过程,并在BFS的同时记录状态即可。
注意模拟倒水时可以直接处理出要倒的水量,不需要写一堆if判断。
void calc(int &x,int &y,int p){
int tmp = min(x,p - y);
x -= tmp;
y += tmp;
}
存储状态可以用map来标记。
代码
#include<bits/stdc++.h>
using namespace std;
int A,B,C;
int res,steps;
struct P{
int a,b,c,steps;
};
map<tuple<int,int,int>,bool> st;
void calc(int &x,int &y,int p){
int tmp = min(x,p - y);
x -= tmp;
y += tmp;
}
void bfs(){
queue<P> q;
q.push({0,0,C,0});
st[{0,0,C}] = true;
res = C;
while(!q.empty()){
int a = q.front().a,b = q.front().b,c = q.front().c,s = q.front().steps;
q.pop();
if(a > 0 && a < res){
res = a;
steps = s;
}
if(b > 0 && b < res){
res = b;
steps = s;
}
if(c > 0 && c < res){
res = c;
steps = s;
}
if(res == 1) return;
int aa,bb,cc;
aa = a,bb = b,cc = c;
calc(aa,bb,B);
if(!st.count({aa,bb,cc})){
q.push({aa,bb,cc,s + 1});
st[{aa,bb,cc}] = true;
}
aa = a,bb = b,cc = c;
calc(aa,cc,C);
if(!st.count({aa,bb,cc})){
q.push({aa,bb,cc,s + 1});
st[{aa,bb,cc}] = true;
}
aa = a,bb = b,cc = c;
calc(bb,aa,A);
if(!st.count({aa,bb,cc})){
q.push({aa,bb,cc,s + 1});
st[{aa,bb,cc}] = true;
}
aa = a,bb = b,cc = c;
calc(bb,cc,C);
if(!st.count({aa,bb,cc})){
q.push({aa,bb,cc,s + 1});
st[{aa,bb,cc}] = true;
}
aa = a,bb = b,cc = c;
calc(cc,aa,A);
if(!st.count({aa,bb,cc})){
q.push({aa,bb,cc,s + 1});
st[{aa,bb,cc}] = true;
}
aa = a,bb = b,cc = c;
calc(cc,bb,B);
if(!st.count({aa,bb,cc})){
q.push({aa,bb,cc,s + 1});
st[{aa,bb,cc}] = true;
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin >> A >> B >> C;
bfs();
cout << res << '\n' << steps;
return 0;
}