题目链接:zoj1005;
这道题是我第一次用广度优先搜索。虽然之前就知道BFS是怎么回事,但是没在具体题目上用过,所以相比DFS,感觉相对生疏。
(虽然这道题网上看到可以用数学方法,很轻松解出;但是为了挑战一下BFS,我还是决定死磕一下)
这道题我看完第一个念头就是搜索。因为每一步就是那几个有限的选择。(虽然题目没说,但是我还是求了最少步骤解出答案的方案,毕竟这种题答案是不唯一的)——考虑到这一点,所以这道题更适合广度优先搜索。
下面是代码(注释比较详细):
#include<bits/stdc++.h>
#include<queue>
using namespace std;
int va,vb,n;
int vis[1000][1000];
struct state
{
int a;
int b;
string way;
};
queue <state> que;
string ope[7]= {"fill A", "fill B","empty A","empty B", "pour A B","pour B A","success"};
int main()
{
while(cin>>va>>vb>>n)
{
memset(vis,0,sizeof(vis));
while(!que.empty())
que.pop(); //初始化操作
state start= {0,0,""}; //表示最开始的时候两个罐子都为空
vis[0][0]=1; //vis[i][j]表示a=i且b=j这个状态之前是否经历过,避免重复操作
struct state current,next;//定义两个状态,分别为当前状态和下一个状态
que.push(start);
while(!que.empty())
{
current=que.front();
que.pop();
// cout<<current.a<<"www"<<endl;
if(current.b==n) //当b罐子中的水已经达到n的时候,停止bfs
{
//输出
// cout<<"ppppp"<<endl;
for(int i=0;i<current.way.length();i++){
cout<<ope[(int)(current.way[i]-'0')]<<endl;
}
cout<<ope[6]<<endl;
break;
}
else
{
next=current;
if(current.a<va) //如果当前状态a罐子没满
{
// cout<<"000"<<endl;
next.a=va;
next.b=current.b;
next.way=current.way+'0';//0是ope数组的下标,表示从current到next的操作是ope[0]
if(vis[next.a][next.b]==0) //说明next这个状态之前没有经历过
{
que.push(next);
vis[next.a][next.b]=1;
}
}
// cout<<"111"<<endl;
//并列的if块体现了广度的意思
if(current.b<vb)
{
next.a=current.a;
next.b=vb;
next.way=current.way+'1';
if(vis[next.a][next.b]==0) //说明next这个状态之前没有经历过
{
que.push(next);
vis[next.a][next.b]=1;
}
}
if(current.a!=0)
{
// cout<<"222"<<endl;
next.a=0;
next.b=current.b;
next.way=current.way+'2';
if(vis[next.a][next.b]==0) //说明next这个状态之前没有经历过
{
que.push(next);
vis[next.a][next.b]=1;
}
}
if(current.b!=0){
// cout<<"333"<<endl;
next.a=current.a;
next.b=0;
next.way=current.way+'3';
if(vis[next.a][next.b]==0) //说明next这个状态之前没有经历过
{
que.push(next);
vis[next.a][next.b]=1;
}
}
if(current.a!=0&¤t.b!=vb){
//a往b中倒水,a倒空且b未溢出
// cout<<"444"<<endl;
if(current.a<=(vb-current.b)){
next.a=0;
next.b=current.b+current.a;
}
//a往b中倒水,b已倒满,a有剩余(a恰倒空已包含在上面的等于中)
else if(current.a>(vb-current.b)){
next.a=current.a-(vb-current.b);
next.b=vb;
}
next.way=current.way+'4';
if(vis[next.a][next.b]==0) //说明next这个状态之前没有经历过
{
que.push(next);
vis[next.a][next.b]=1;
}
}
if(current.a!=va&¤t.b!=0){
// cout<<"555"<<endl;
//b往a中倒水,b倒空且a未溢出
if(current.b<=(va-current.a)){
next.a=current.a+current.b;
next.b=0;
}
//b往a中倒水,a已倒满,b有剩余(a恰倒空已包含在上面的等于中)
else if(current.b>(va-current.a)){
next.a=va;
next.b=current.b-(va-current.a);
}
next.way=current.way+'5';
if(vis[next.a][next.b]==0) //说明next这个状态之前没有经历过
{
que.push(next);
vis[next.a][next.b]=1;
}
}
}
}
}
return 0;
}