题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1495
非常可乐
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 16814 Accepted Submission(s): 6805
题解:
1.由于每个容器不超过100, 所以枚举所有状态(1e6)也不会超时。所以直接用BFS。
2.判重:
2.1:其中S<=100, 1<=N<100, 1<=M<100,所以可以将当前三个容器的可乐量压缩成一个int类型,且最大不超过1009999(S放在前面,如果放在中间或者后面,就要加多一位了,这里有讲究),然后就可以开个vis[]数组直接检查状态status是否已经访问过了。
2.2:其实不用把三个容器压缩成一个int类型,可以直接开个三维数组vis[110][110][110],每一维对应一个容器,也是1e6级别的大小,而且更加方便灵活。
2.3:其实开二维数组就够了,因为总的可乐量是确定的,当其中两个容器的可乐量确定了,那剩下的容器的可乐量也就确定了。这一个简单的优化又把内存消耗降低了100倍。
关于判重,目前自己有三个习惯的方法:STL的set、vis多维判重 与 vis status(int类型的以为判重) 。
1. set判重,适用状态高度离散的判重(开数组不能满足其范围), 特点慢,能用数组判重就尽量不要用set判重。
2.vis多维判重, 适用于状态集中且维度较少的情况。
3.staus判重,适用于状态集中且维度较多的情况, 其本质就是把所有维度的状态都压缩成一个int类型, 所以status本质是一个哈希值。
2.1(status判重):
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <vector> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 #define ms(a,b) memset((a),(b),sizeof((a))) 13 using namespace std; 14 typedef long long LL; 15 const int INF = 2e9; 16 const LL LNF = 9e18; 17 const int MOD = 1e9+7; 18 const int MAXN = 2e6+10; 19 20 //0为容器S, 1为容器N, 2为容器M 21 struct node 22 { 23 int status, con[3], step; //con[i]为容器i当前盛的可乐体积 24 }; 25 int vol[3], vis[MAXN]; //vol[i]为容器i的容量 26 27 queue<node>que; 28 int bfs() 29 { 30 ms(vis,0); 31 while(!que.empty()) que.pop(); 32 33 node now, tmp; 34 now.con[0] = vol[0]; //初始状态只用容器S盛有可乐 35 now.con[1] = now.con[2] = 0; 36 now.status = vol[0]*10000; //初始的状态 37 now.step = 0; 38 vis[now.status] = 1; 39 que.push(now); 40 41 while(!que.empty()) 42 { 43 now = que.front(); 44 que.pop(); 45 46 // cout<< now.status <<endl; 47 if((now.con[0]==vol[0]/2 && now.con[1]==vol[0]/2) 48 || (now.con[0]==vol[0]/2 && now.con[2]==vol[0]/2) 49 || (now.con[1]==vol[0]/2 && now.con[2]==vol[0]/2)) 50 return now.step; 51 52 for(int i = 0; i<3; i++) //模拟倒水的过程, i为倒, j为被倒 53 for(int j = 0; j<3; j++) 54 { 55 if(i==j) continue; 56 tmp = now; 57 int pour = min(tmp.con[i], vol[j]-tmp.con[j]); //能倒多少水 58 tmp.con[j] += pour; 59 tmp.con[i] -= pour; 60 tmp.status = tmp.con[0]*10000+tmp.con[1]*100+tmp.con[2]; //更新状态 61 if(!vis[tmp.status]) 62 { 63 vis[tmp.status] = 1; 64 tmp.step++; 65 que.push(tmp); 66 } 67 } 68 } 69 return -1; 70 } 71 72 int main() 73 { 74 while(scanf("%d%d%d",&vol[0], &vol[1], &vol[2]) && (vol[0]||vol[1]||vol[2])) 75 { 76 if(vol[0]%2) //奇数肯定不能平分 77 { 78 printf("NO "); 79 continue; 80 } 81 int ans = bfs(); 82 if(ans==-1) 83 printf("NO "); 84 else 85 printf("%d ", ans); 86 } 87 return 0; 88 }
2.2(三维判重):
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <vector> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 #define ms(a,b) memset((a),(b),sizeof((a))) 13 using namespace std; 14 typedef long long LL; 15 const int INF = 2e9; 16 const LL LNF = 9e18; 17 const int MOD = 1e9+7; 18 const int MAXN = 100+10; 19 20 struct node 21 { 22 int con[3], step; 23 }; 24 int vol[3], vis[MAXN][MAXN][MAXN]; 25 26 queue<node>que; 27 int bfs() 28 { 29 ms(vis,0); 30 while(!que.empty()) que.pop(); 31 32 node now, tmp; 33 now.con[0] = vol[0]; 34 now.con[1] = now.con[2] = 0; 35 now.step = 0; 36 vis[now.con[0]][now.con[1]][now.con[2]] = 1; 37 que.push(now); 38 39 while(!que.empty()) 40 { 41 now = que.front(); 42 que.pop(); 43 44 if((now.con[0]==vol[0]/2 && now.con[1]==vol[0]/2) 45 || (now.con[0]==vol[0]/2 && now.con[2]==vol[0]/2) 46 || (now.con[1]==vol[0]/2 && now.con[2]==vol[0]/2)) 47 return now.step; 48 49 for(int i = 0; i<3; i++) //模拟倒水的过程 50 for(int j = 0; j<3; j++) 51 { 52 if(i==j) continue; 53 tmp = now; 54 int pour = min(tmp.con[i], vol[j]-tmp.con[j]); 55 tmp.con[j] += pour; 56 tmp.con[i] -= pour; 57 if(!vis[tmp.con[0]][tmp.con[1]][tmp.con[2]]) 58 { 59 vis[tmp.con[0]][tmp.con[1]][tmp.con[2]] = 1; 60 tmp.step++; 61 que.push(tmp); 62 } 63 } 64 } 65 return -1; 66 } 67 68 int main() 69 { 70 while(scanf("%d%d%d",&vol[0], &vol[1], &vol[2]) && (vol[0]||vol[1]||vol[2])) 71 { 72 if(vol[0]%2) 73 { 74 printf("NO "); 75 continue; 76 } 77 int ans = bfs(); 78 if(ans==-1) 79 printf("NO "); 80 else 81 printf("%d ", ans); 82 } 83 return 0; 84 }
2.3(二维判重,推荐使用):
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <vector> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 #define ms(a,b) memset((a),(b),sizeof((a))) 13 using namespace std; 14 typedef long long LL; 15 const int INF = 2e9; 16 const LL LNF = 9e18; 17 const int MOD = 1e9+7; 18 const int MAXN = 100+10; 19 20 struct node 21 { 22 int con[3], step; 23 }; 24 int vol[3], vis[MAXN][MAXN]; 25 26 queue<node>que; 27 int bfs() 28 { 29 ms(vis,0); 30 while(!que.empty()) que.pop(); 31 32 node now, tmp; 33 now.con[0] = vol[0]; 34 now.con[1] = now.con[2] = 0; 35 now.step = 0; 36 vis[now.con[0]][now.con[1]] = 1; 37 que.push(now); 38 39 while(!que.empty()) 40 { 41 now = que.front(); 42 que.pop(); 43 44 if((now.con[0]==vol[0]/2 && now.con[1]==vol[0]/2) 45 || (now.con[0]==vol[0]/2 && now.con[2]==vol[0]/2) 46 || (now.con[1]==vol[0]/2 && now.con[2]==vol[0]/2)) 47 return now.step; 48 49 for(int i = 0; i<3; i++) //模拟倒水的过程 50 for(int j = 0; j<3; j++) 51 { 52 if(i==j) continue; 53 tmp = now; 54 int pour = min(tmp.con[i], vol[j]-tmp.con[j]); 55 tmp.con[j] += pour; 56 tmp.con[i] -= pour; 57 if(!vis[tmp.con[0]][tmp.con[1]]) 58 { 59 vis[tmp.con[0]][tmp.con[1]] = 1; 60 tmp.step++; 61 que.push(tmp); 62 } 63 } 64 } 65 return -1; 66 } 67 68 int main() 69 { 70 while(scanf("%d%d%d",&vol[0], &vol[1], &vol[2]) && (vol[0]||vol[1]||vol[2])) 71 { 72 if(vol[0]%2) 73 { 74 printf("NO "); 75 continue; 76 } 77 int ans = bfs(); 78 if(ans==-1) 79 printf("NO "); 80 else 81 printf("%d ", ans); 82 } 83 return 0; 84 }