题目链接:hdu 1495
题目大意
- 一瓶可乐容量是S,只有两个没有刻度的杯子,容量分别是a和b,可乐杯子之间可以相互倒
- 由于没有刻度,那么就肯定是要么倒完,要么倒满
- 问是否能平分这一瓶可乐,如果可以输出最少倒的次数,否则输出"NO"
思路
- bfs
- 用广搜模拟六种情况,就是s->a,s->b,a->s,a->b,b->s,b->a这六种情况,s->a表示拿s往a中倒可乐,然后记录步数
- 当三个容器中出现两个容量是s/2,另外一个是0的情况,说明可以平分,输出步数
- 拿set记录状态,如果出现过了,就不再进队列,如果出队列还没返回值,直接返回-1
- 如果返回-1,则输出"NO"
ac代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct node{
int s, a, b, dep;
};
int s, a, b;
bool ok(node a){
vector<int> v;
int ss = 0;
v.push_back(a.s);
v.push_back(a.a);
v.push_back(a.b);
sort(v.begin(), v.end()); //排序方便看最大最小值
return v[0] == 0 && v[1] == s / 2 && v[2] == s / 2;
}
int bfs(){
set<string> ss;
queue<node> q;
q.push({s, 0, 0, 0}); //初始状态
while(q.size()){
node t = q.front(); q.pop();
string aa = to_string(t.s) + "-" + to_string(t.a) + "-" + to_string(t.b); //把状态转换成字符串
if(ss.count(aa)) continue; //set记录状态
ss.insert(aa);
if(ok(t)) {
return t.dep; //返回步数
}
node tmp;
//s -> a
tmp = t; tmp.dep ++;
tmp.a += tmp.s; tmp.s = 0; //先全部倒完
if(tmp.a >= a) tmp.s += tmp.a - a, tmp.a = a;//多余部分还给s容器
q.push(tmp); //下同
//s -> b
tmp = t; tmp.dep ++;
tmp.b += tmp.s; tmp.s = 0;
if(tmp.b >= b) tmp.s += tmp.b - b, tmp.b = b;
q.push(tmp);
//a -> s
tmp = t; tmp.dep ++;
tmp.s += tmp.a; tmp.a = 0; //s不会超,所以没必要判断是否会多余
q.push(tmp);
//a -> b
tmp = t; tmp.dep ++;
tmp.b += tmp.a; tmp.a = 0;
if(tmp.b >= b) tmp.a += tmp.b - b, tmp.b = b;
q.push(tmp);
//b -> s
tmp = t; tmp.dep ++;
tmp.s += tmp.b; tmp.b = 0;
q.push(tmp);
//b -> a
tmp = t; tmp.dep ++;
tmp.a += tmp.b; tmp.b = 0;
if(tmp.a >= a) tmp.b += tmp.a - a, tmp.a = a;
q.push(tmp);
}
return -1; //如果还不行则返回-1
}
int main(){
while(~scanf("%d%d%d", &s, &a, &b)){
if(s + a + b == 0) break;
int ans = bfs();
if(ans == -1) puts("NO");
else printf("%d\n", ans);
}
return 0;
}