首页 > 代码库 > HDU-1495 非常可乐 (嵌套结构体-广搜 对比 一般广搜)
HDU-1495 非常可乐 (嵌套结构体-广搜 对比 一般广搜)
题意
Input
三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。Output如果能平分的话请输出最少要倒的次数,否则输出"NO"。Sample Input
7 4 3 4 1 3 0 0 0
Sample Output
NO 3
---------------------------------------------------------我是分割线----------------------------------------------------------------------------------------------------------------------
某童靴的一般思路 (感谢@陌类 提供的代码)
(较麻烦的题解, 好像多数人都这么写~ 并且学长们还老爱出这道题目来****, 每每写这道题总是忍着**加**)
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #include <queue> 5 #define N 110 6 using namespace std; 7 int vis[N][N][N]; 8 int s,n,m; 9 struct node 10 { 11 int n,s,m,step; 12 }; 13 int cheak(int x,int y,int z) 14 { 15 if(x==0&&y==z) 16 return 1; 17 if(y==0&&x==z) 18 return 1; 19 if(z==0&&x==y) 20 return 1; 21 return 0; 22 } 23 int bfs() 24 { 25 queue<node>Q; 26 node now,next; 27 now.s=s; 28 now.n=0; 29 now.m=0; 30 now.step=0; 31 vis[s][0][0]=1; 32 Q.push(now); 33 while(Q.size()) 34 { 35 now=Q.front(); 36 Q.pop(); 37 if(cheak(now.s,now.n,now.m))//检查状态 38 { 39 return now.step; 40 } 41 for(int i=1;i<=6;i++) 42 { 43 if(now.s!=0) 44 { 45 if(i==1&&now.n!=n) 46 { 47 if(now.n+now.s>n) 48 { 49 next.n=n; 50 next.s=now.s-(n-now.n); 51 } 52 else 53 { 54 next.n=now.n+now.s; 55 next.s=0; 56 } 57 next.m=now.m; 58 next.step=now.step+1; 59 if(!vis[next.s][next.n][next.m]) 60 { 61 vis[next.s][next.n][next.m]=1; 62 Q.push(next); 63 } 64 } 65 else if(i==2&&now.s!=0&&now.m!=m) 66 { 67 if(now.m+now.s>m) 68 { 69 next.m=m; 70 next.s=now.s-(m-now.m); 71 } 72 else 73 { 74 next.m=now.m+now.s; 75 next.s=0; 76 } 77 next.n=now.n; 78 next.step=now.step+1; 79 if(!vis[next.s][next.n][next.m]) 80 { 81 vis[next.s][next.n][next.m]=1; 82 Q.push(next); 83 } 84 } 85 } 86 if(now.n!=0) 87 { 88 if(i==3&&now.m!=m) 89 { 90 if(now.m+now.n>m) 91 { 92 next.m=m; 93 next.n=now.n-(m-now.m); 94 } 95 else 96 { 97 next.m=now.m+now.n; 98 next.n=0; 99 } 100 next.s=now.s; 101 next.step=now.step+1; 102 if(!vis[next.s][next.n][next.m]) 103 { 104 vis[next.s][next.n][next.m]=1; 105 Q.push(next); 106 } 107 } 108 else if(i==4&&now.n!=0&&now.s!=s) 109 { 110 if(now.m+now.s>s) 111 { 112 next.s=s; 113 next.n=now.n-(s-now.s); 114 } 115 else 116 { 117 next.s=now.n+now.s; 118 next.n=0; 119 } 120 next.m=now.m; 121 next.step=now.step+1; 122 if(!vis[next.s][next.n][next.m]) 123 { 124 vis[next.s][next.n][next.m]=1; 125 Q.push(next); 126 } 127 } 128 } 129 if(now.m!=0) 130 { 131 if(i==5&&now.m!=0&&now.n!=n) 132 { 133 if(now.n+now.m>n) 134 { 135 next.n=n; 136 next.m=now.m-(n-now.n); 137 } 138 else 139 { 140 next.n=now.n+now.m; 141 next.m=0; 142 } 143 next.s=now.s; 144 next.step=now.step+1; 145 if(!vis[next.s][next.n][next.m]) 146 { 147 vis[next.s][next.n][next.m]=1; 148 Q.push(next); 149 } 150 } 151 else if(i==6&&now.m!=0&&now.s!=s) 152 { 153 if(now.s+now.m>s) 154 { 155 next.s=s; 156 next.m=now.m-(s-now.s); 157 } 158 else 159 { 160 next.s=now.s+now.m; 161 next.m=0; 162 } 163 next.n=now.n; 164 next.step=now.step+1; 165 if(!vis[next.s][next.n][next.m]) 166 { 167 vis[next.s][next.n][next.m]=1; 168 Q.push(next); 169 } 170 } 171 172 } 173 } 174 } 175 return -1; 176 } 177 int main() 178 { 179 while(scanf("%d%d%d",&s,&n,&m),s+n+m!=0) 180 { 181 if(s%2!=0) 182 { 183 printf("NO\n"); 184 } 185 else 186 { 187 memset(vis,0,sizeof(vis)); 188 int ans; 189 ans=bfs(); 190 if(ans>=0) 191 printf("%d\n",ans); 192 else 193 printf("NO\n"); 194 } 195 } 196 return 0; 197 }
简单点评
在上面的代码, 每次for循环都将枚举六种情况 ,1->2 , 1-》3,2-》3 ,2-》1,3-》1,3-》2 ,并且每种情况又要分为两种来讨论......
重复的部分太多了~
重复的部分太多了~
不够简洁,代码太长长了。
出错误了一不好找啊!
-------------------------------------------------------------------------------------------------------------------------------------我是分割线---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
起先我也是这么做的,后来我想了一个相对简单的优化办法:
进行结构体的嵌套 ,结构体cup 的 a[1]/a[2]/a[3]分别代表这 三个容器 ,其中结构体 cup中 up 代表一个容器的装水上限 ,now 代表现在的水量! 再用 结构体node 将cup和step 封装起来!
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> //by @山枫叶纷飞 5 #include<cstdlib> 6 #include<cmath> 7 #include<string> 8 #include<set> 9 #include<queue> 10 using namespace std; 11 typedef long long ll; 12 double dinf=99999999.9, mm=1e-8; 13 const int N=108,inf=0x3f3f3f3f; 14 int s,n,m; 15 int vis[N][N][N]; 16 struct cup 17 { 18 int up,now; 19 }; 20 struct node 21 { 22 cup a[4]; ///进行结构体的嵌套 ,a[1]/a[2]/a[3] 分别表示三个容器 23 int step; 24 }; 25 int bfs( ) 26 { 27 int i,j,k; 28 queue<node>Q; 29 node p,q; 30 p.a[1].now=s;p.a[1].up=s; 31 p.a[2].now=0;p.a[2].up=n; 32 p.a[3].now=0;p.a[3].up=m; 33 p.step=0; 34 memset(vis,0,sizeof(vis));vis[s][0][0]=1; 35 Q.push(p); 36 while(Q.size()>0) 37 { 38 p=Q.front(); ///从队列中取到的现在的状态 39 Q.pop(); 40 if((p.a[1].now==s/2&&p.a[2].now==s/2) || (p.a[1].now==s/2&&p.a[3].now==s/2))///判断是否达到预期结果 41 return p.step; 42 if((p.a[2].now==s/2&&p.a[3].now==s/2))///判断是否达到预期结果(太长了,拆成了两段) 43 return p.step; 44 45 for(i=1;i<=3;i++) 46 { 47 for(j=1;j<=3;j++) 48 { 49 if(i==j || p.a[i].now==0||p.a[j].now==p.a[j].up)///简易排除 50 continue; 51 52 q=p;///初始化,q 代表由p 延伸来的下一状态 53 54 int dif=p.a[j].up-p.a[j].now;///表示容器a[j]最多可添加水量 55 if(p.a[i].now>=dif)///若容器a[j]可被填满水 56 { 57 q.a[i].now=p.a[i].now-dif; 58 q.a[j].now=p.a[j].up; 59 } 60 else ///若容器a[j]不能装满水 61 { 62 q.a[i].now=0; 63 q.a[j].now=p.a[i].now+p.a[j].now; 64 } 65 q.step=p.step+1; 66 if(vis[q.a[1].now][q.a[2].now][q.a[3].now]==0) 67 { 68 vis[q.a[1].now][q.a[2].now][q.a[3].now]=1; 69 Q.push(q); 70 } 71 } 72 } 73 74 75 } 76 return -1; 77 } 78 int main() 79 { 80 while(scanf("%d%d%d",&s,&n,&m),s+n+m) 81 { 82 if(s%2!=0)///奇数一定无法均分成两份 83 printf("NO\n"); 84 else 85 { 86 int k=bfs(); 87 if(k==-1) 88 printf("NO\n"); 89 else 90 printf("%d\n",k); 91 } 92 } 93 94 return 0; 95 }
简单点评
两重for 循环,用a[i] 和a[j] 来模拟全部六种情况的倒水过程 ,省了超过100行的代码, 结构体的含义一目了然, 就是结构体名字写起来太长了!
还有要注意的是: { q=p;///初始化,q 代表由p 延伸来的下一状态}这段代码的位置很重要, 每次新的内层for循环都要记得将q重新初始化, 不然会造成意料之外的错误! 当时debug 到了 "debug人在天涯"!
---------------------------------------------------------我是分割线----------------------------------------------------------------------------------------------------------------------
其他思路
这个题目用数论也是可以做的! 近似玄学 , 最近正在整理中!敬请期待!
HDU-1495 非常可乐 (嵌套结构体-广搜 对比 一般广搜)