HDOJ搜索专题之非常可乐
题目模型:给定3个无刻度容器,容器的容积均为正整数,初始状态为第一个容器装满水,其它2个空着,问是否能将第一个容器中的水平分,若能输出最少操作步数,否则输出"NO".
分析:典型的状态空间搜索题,要求最少步数,可以用BFS,将3个容器中中的水量组合定义为状态,倒水操作会造成状态转移。目标状态为某两个容器中水量相等且总和为总水量。一个小的优化是当总水量为奇数时,直接输出"NO".
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 #define N 101 5 #define MIN(a,b) ((a)<(b)?(a):(b)) 6 using namespace std; 7 typedef struct node 8 { 9 int v[3]; 10 int t; 11 }node; 12 node cur,next; 13 queue<node> Q; 14 int c[3]; 15 char vis[N][N]; 16 bool is_ok(node tmp) 17 { 18 for(int i=0;i<3;i++) 19 { 20 for(int j=i+1;j<3;j++) 21 { 22 if(tmp.v[i]==tmp.v[j] && tmp.v[i]+tmp.v[j]==c[0]) return true; 23 } 24 } 25 return false; 26 } 27 node st_tran(node tmp,int i,int j) 28 { 29 int d=MIN(tmp.v[i],c[j]-tmp.v[j]); 30 if(d==0) tmp.t=-1; 31 else 32 { 33 tmp.v[i]-=d; 34 tmp.v[j]+=d; 35 tmp.t++; 36 } 37 return tmp; 38 } 39 void bfs() 40 { 41 bool success=false; 42 int ans; 43 while(!Q.empty()) Q.pop(); 44 memset(vis,0,sizeof(vis)); 45 cur.v[0]=c[0]; 46 cur.v[1]=0; 47 cur.v[2]=0; 48 cur.t=0; 49 vis[cur.v[0]][cur.v[1]]=1; 50 Q.push(cur); 51 while(!Q.empty() && !success) 52 { 53 cur=Q.front(),Q.pop(); 54 if(is_ok(cur)) success=true,ans=cur.t; 55 for(int i=0;!success && i<3;i++) 56 { 57 for(int j=0;!success && j<3;j++) 58 { 59 if(i==j) continue; 60 next=st_tran(cur,i,j); 61 if(next.t==-1 || vis[next.v[0]][next.v[1]]) continue; 62 if(is_ok(next)) success=true,ans=next.t; 63 else vis[next.v[0]][next.v[1]]=1,Q.push(next); 64 } 65 } 66 } 67 if(success) printf("%d\n",ans); 68 else puts("NO"); 69 } 70 int main() 71 { 72 while(scanf("%d%d%d",&c[0],&c[1],&c[2])&&c[0]) 73 { 74 if(c[0]%2) puts("NO"); 75 else bfs(); 76 } 77 return 0; 78 }