题目的思路还是很简单的:
因为要求最优解,广度优先搜索,对倒酒的六种操作进行遍历就行了。
然而:
在这个题上作者至少卡了小半天。下面就是作者找到的一些WA点。1.在记录是否被遍历过的状态时,用vis[N][N],来记录是否被遍历过。因为确定了其中两个瓶子,第三个瓶子的状态自然就知道了。关键时,记录的时候,要用后两个瓶子的装酒状态,因为,如果用前两个瓶子的装酒状态的话。s里的酒比a和b瓶子里的酒都要多,若N太小会溢出。而若N太大可能会MLT或者TL。2.广度优先搜索一定会有一个出栈的过程。一定要养成一个良好的编代码的习惯。3.思路一定要清晰,在进行状态变化的时候,一定要注意,不要GG了。
代码如下:
#include <iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
#define N 105
struct node{
int a,b,s;
int step;
}ST;
int a,b,s;
int vis[N][N];
int bfs()
{
queue<node> q;
ST.s=s;
ST.a=0;
ST.b=0;
ST.step=0;
q.push(ST);
vis[0][0]=1;
while(!q.empty())
{
if(q.front().a==s/2&&q.front().s==s/2)
{
return q.front().step;
}
node tmp;
int S=q.front().s;
int A=q.front().a;
int B=q.front().b;
int Step=q.front().step;
int C;
if(S&&A!=a)
{
C=a-A;
if(S>=C)tmp.s=S-C,tmp.a=a;
else tmp.s=0,tmp.a=A+S;
tmp.b=B;tmp.step=Step+1;
if(!vis[tmp.a][tmp.b]){
vis[tmp.a][tmp.b]=1;
q.push(tmp);
}
}
if(S&&B!=b)
{
C=b-B;
if(S>=C)tmp.s=S-C,tmp.b=b;
else tmp.s=0,tmp.b=B+S;
tmp.a=A;tmp.step=Step+1;
if(!vis[tmp.a][tmp.b]){
vis[tmp.a][tmp.b]=1;
q.push(tmp);
}
}
if(A&&S!=s)
{
C=s-S;
if(A>=C)tmp.a=A-C,tmp.s=s;
else tmp.a=0,tmp.s=S+A;
tmp.b=B;tmp.step=Step+1;
if(!vis[tmp.a][tmp.b]){
vis[tmp.a][tmp.b]=1;
q.push(tmp);}
}
if(B&&S!=s)
{
C=s-S;
if(C<=B) tmp.b=B-C,tmp.s=s;
else tmp.b=0,tmp.s=S+B;
tmp.a=A;tmp.step=Step+1;
if(!vis[tmp.a][tmp.b]){
vis[tmp.a][tmp.b]=1;
q.push(tmp);}
}
if(B&& A!=a)
{
C=a-A;
if(C<=B)tmp.b=B-C,tmp.a=a;
else tmp.b=0,tmp.a=A+B;
tmp.s=S;tmp.step=Step+1;
if(!vis[tmp.a][tmp.b]){
tmp.step=Step+1;
vis[tmp.a][tmp.b]=1;
q.push(tmp);}
}
if(A&&B!=b)
{
C=b-B;
if(C<=A) tmp.a=A-C,tmp.b=b;
else tmp.a=0,tmp.b=B+A;
tmp.s=S;tmp.step=Step+1;
if(!vis[tmp.a][tmp.b]){
vis[tmp.a][tmp.b]=1;
q.push(tmp);}
}
q.pop();
}
return 0;
}
int main()
{
while(cin>>s>>a>>b,s+a+b)
{
memset(vis,0,sizeof(vis));
if(s%2==1){cout<<"NO"<<endl;continue;}
if(a<b)swap(a,b);
int ans;
ans= bfs();
if(!ans)cout<<"NO"<<endl;
else cout<<ans<<endl;
}
return 0;
}