NYOJ #21 三个水杯(bfs)
描述
给出三个水杯,大小不一,并且只有最大的水杯的水是装满的,其余两个为空杯子。三个水杯之间相互倒水,并且水杯没有标识,只能根据给出的水杯体积来计算。现在要求你写出一个程序,使其输出使初始状态到达目标状态的最少次数。
输入
第一行一个整数N(0<N<50)表示N组测试数据
接下来每组测试数据有两行,第一行给出三个整数V1 V2 V3 (V1>V2>V3 V1<100 V3>0)表示三个水杯的体积。
第二行给出三个整数E1 E2 E3 (体积小于等于相应水杯体积)表示我们需要的最终状态。
输出
每行输出相应测试数据最少的倒水次数。如果达不到目标状态输出-1。
样例输入
2 6 3 1 4 1 1 9 3 2 7 1 1
样例输出
3 -1
解题思路:bfs求最少的倒水次数,每次都有6种倒水可能,标记一下三个水杯的容量状态,用队列来模拟倒水过程,如果出现某个过程达到最终的倒水状态,则直接返回其倒水次数;否则直到队空,返回-1,说明不能到达最终的容量状态。详解看代码。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int t,Vmax[3],Est[3],Cur[3]; 4 bool vis[105][105][105]; 5 struct node{int a,b,c,step;}cur,tmp; 6 queue<node> que; 7 int bfs(int x){ 8 while(!que.empty())que.pop(); 9 cur.a=x,cur.b=cur.c=cur.step=0; 10 vis[cur.a][cur.b][cur.c]=true; 11 que.push(cur); 12 while(!que.empty()){ 13 cur=que.front();que.pop(); 14 if(cur.a==Est[0]&&cur.b==Est[1]&&cur.c==Est[2])return cur.step;//到达最终的状态 15 for(int i=0;i<3;++i){ 16 for(int j=0;j<3;++j){//6种倒水可能 17 tmp=cur;Cur[0]=tmp.a,Cur[1]=tmp.b,Cur[2]=tmp.c;//每次重新赋值 18 if(i!=j&&Cur[i]>0&&Cur[j]<Vmax[j]){//i-->j,如果第i个桶的水量大于0,并且第j个桶的水量不超过其最大容量 19 int gg=min(Cur[i],Vmax[j]-Cur[j]);//如果第j个桶剩余容量小于第i个桶里的水量,那么只能倒Vmax[j]-Cur[j];反之,将第i个桶的水量全部倒给第j个桶 20 Cur[i]-=gg,Cur[j]+=gg;// i--->j 21 if(!vis[Cur[0]][Cur[1]][Cur[2]]){//状态未出现过 22 vis[Cur[0]][Cur[1]][Cur[2]]=true; 23 tmp.a=Cur[0],tmp.b=Cur[1],tmp.c=Cur[2];//重新赋值 24 tmp.step++; 25 que.push(tmp); 26 } 27 } 28 } 29 } 30 } 31 return -1;//不满足条件则返回-1 32 } 33 int main(){ 34 while(cin>>t){ 35 while(t--){ 36 for(int i=0;i<3;++i)cin>>Vmax[i]; 37 for(int i=0;i<3;++i)cin>>Est[i]; 38 memset(vis,false,sizeof(vis)); 39 cout<<bfs(Vmax[0])<<endl; 40 } 41 } 42 return 0; 43 }