非常可乐(BFS和最短路)
来源:互联网 发布:网红穆雅斓的淘宝店铺 编辑:程序博客网 时间:2024/05/17 03:00
原题链接
非常可乐
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Submit
Status
Description
大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出”NO”。
Input
三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以”0 0 0”结束。
Output
如果能平分的话请输出最少要倒的次数,否则输出”NO”。
Sample Input
7 4 3
4 1 3
0 0 0
Sample Output
NO
3
问题很简单,其实就是模拟倒可乐的过程,但是每次倒都有多种选择,而且又让求出最少倒多少次,所以只能用BFS。总结一下
同时,BFS其实就是每步的代价为1的最短路问题,最短路每次到达一个状态后,都会更新下这个状态下的最大值,并且如果能够更新那么他的下一步也会加入队列中去,否则不会加入到队列中。同时对于每个状态除了判断是否走过的vis数组,还会有一个初始值是-1的in数组用来统计是否有最短路和最短路是多大。最后不断地对队列进行循环,对于BFS,如果中间有解就直接输出了,那就是最优解,如果是最短路那么只需要更新到这个状态的最短路径即可,最后循环完后输出无解或者是有最优解即可。SPFA和BFS的区别就在于BFS只进一次队,SPFA(最短路)进若干次队
#include <cstdio>#include <cstring>#include <iostream>#include <queue>#include <algorithm>using namespace std;const int maxn=102;typedef struct node{ int a[3];}node;node c;//这里的c代表三个瓶子的容量上限int in[maxn][maxn][maxn];//初始值为-1,当存有次数的统计值时,就不是-1了bool vis[maxn][maxn][maxn];bool cmp(int x,int y){ return x>y;}//检查now.a[i]向now.a[j]中倒可乐是否可行,同时如果可以就修改newx中的值bool can(node now,node& newx,int i,int j){ int shengyu = c.a[j] - now.a[j]; if(shengyu <= 0) return false; for(int k=0;k<3;k++) if(k!=i&&k!=j) newx.a[k]=now.a[k]; if(shengyu > now.a[i]){ newx.a[i]=0; newx.a[j]=now.a[i]+now.a[j]; } else{ newx.a[i]=now.a[i]-shengyu; newx.a[j]=c.a[j]; } if(vis[newx.a[0]][newx.a[1]][newx.a[2]]) return false; else return true;}void BFS(node t){ memset(in,-1,sizeof(in)); memset(vis,false,sizeof(vis));//false说明可以访问 queue<node> q; q.push(t); vis[t.a[0]][t.a[1]][t.a[2]]=true; in[t.a[0]][t.a[1]][t.a[2]]=0; while(!q.empty()){ node now=q.front(); q.pop(); for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(i!=j){ node newx; if(can(now,newx,i,j)){ //q.push(newx);就算算了之后是可以倒过去的,但是现在仍然不能入队 int res = in[now.a[0]][now.a[1]][now.a[2]] + 1;//BFS就是每一步代价都是1的最短路,这里日后还可以改成最短路的 if(in[newx.a[0]][newx.a[1]][newx.a[2]] == -1 || res < in[newx.a[0]][newx.a[1]][newx.a[2]]){ in[newx.a[0]][newx.a[1]][newx.a[2]] = res; if(!vis[newx.a[0]][newx.a[1]][newx.a[2]]){ q.push(newx); vis[newx.a[0]][newx.a[1]][newx.a[2]]=true; } } } } } } } //分配完成的情况就是最大的两个瓶子里把所有的可乐都平分了 if(c.a[1]>=c.a[2]){ int mid=c.a[0]/2; if(in[mid][mid][0]==-1) cout << "NO" <<endl; else cout << in[mid][mid][0] << endl; } else{ int mid=c.a[0]/2; if(in[mid][0][mid]==-1) cout << "NO" <<endl; else cout << in[mid][0][mid] << endl; }}int main(){ while(scanf("%d%d%d",&c.a[0],&c.a[1],&c.a[2])==3 && !(c.a[0]==0 && c.a[1]==0 && c.a[2]==0)){ if(c.a[0] % 2 == 1) cout << "NO" << endl; else{ node t; t.a[0]=c.a[0]; t.a[1]=0; t.a[2]=0;//将饮料的数量初始化 BFS(t); } } return 0;}
上面这个代码是通过的,但是下面这个代码不行,虽然他的对于下标的运算要更快,但是已经开的空间实在是太大了,而本题由于边最大到100,所以也不能用*1,*100,*10000来解决。但是对于范围小的题来说,这样的下标运算是要快很多的
下面给出超空间的代码
#include <cstdio>#include <cstring>#include <iostream>#include <queue>#include <algorithm>using namespace std;typedef struct node{ int a[3];}node;node c;//这里的c代表三个瓶子的容量上限int in[20000000];//初始值为-1,当存有次数的统计值时,就不是-1了bool vis[20000000];//假设三个杯子的从大到小的顺序是a[0],a[1],a[2],那么下标为a[0] + (a[1]<<7) + (a[2]<<14);bool cmp(int x,int y){ return x>y;}//检查now.a[i]向now.a[j]中倒可乐是否可行,同时如果可以就修改newx中的值bool can(node now,node& newx,int i,int j){ int shengyu = c.a[j] - now.a[j]; if(shengyu <= 0) return false; for(int k=0;k<3;k++) if(k!=i&&k!=j) newx.a[k]=now.a[k]; if(shengyu > now.a[i]){ newx.a[i]=0; newx.a[j]=now.a[i]+now.a[j]; } else{ newx.a[i]=now.a[i]-shengyu; newx.a[j]=c.a[j]; } if(vis[newx.a[0] + (newx.a[1]<<7) + (newx.a[2]<<14)]) return false; //注意这里所有的位运算都要加括号括起来,否则会出现把后面的数也算进去的结果 else return true;}void BFS(node t){ memset(in,-1,sizeof(in)); memset(vis,false,sizeof(vis));//false说明可以访问 queue<node> q; q.push(t); vis[t.a[0] + (t.a[1]<<7) + (t.a[2]<<14)]=true; in[t.a[0] + (t.a[1]<<7) + (t.a[2]<<14)]=0; while(!q.empty()){ node now=q.front(); q.pop(); int nowloc = now.a[0] + (now.a[1]<<7) + (now.a[2]<<14); //cout << now.a[0] <<' ' << now.a[1] << ' ' << now.a[2] << endl; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(i!=j){ node newx; if(can(now,newx,i,j)){ //q.push(newx);就算算了之后是可以倒过去的,但是现在仍然不能入队列 int newxloc = newx.a[0] + (newx.a[1]<<7) + (newx.a[2]<<14); int res = in[nowloc] + 1;//BFS就是每一步代价都是1的最短路,这里日后还可以改成最短路的 if(in[newxloc] == -1 || res < in[newxloc]){ in[newxloc] = res; if(!vis[newxloc]){ q.push(newx); vis[newxloc]=true; } } } } } } } //分配完成的情况就是最大的两个瓶子里把所有的可乐都平分了 if(c.a[1]>=c.a[2]){ int mid=c.a[0]/2; if(in[mid + (mid<<7)]==-1) cout << "NO" <<endl; else cout << in[mid + (mid<<7)] << endl; } else{ int mid=c.a[0]/2; if(in[mid + (mid<<14)]==-1) cout << "NO" <<endl; else cout << in[mid + (mid<<14)] << endl; }}int main(){ while(scanf("%d%d%d",&c.a[0],&c.a[1],&c.a[2])==3 && !(c.a[0]==0 && c.a[1]==0 && c.a[2]==0)){ if(c.a[0] % 2 == 1) cout << "NO" << endl; else{ node t; t.a[0]=c.a[0]; t.a[1]=0; t.a[2]=0;//将饮料的数量初始化 BFS(t); } } return 0;}
- 非常可乐(BFS和最短路)
- HDU 1495 非常可乐 (BFS求最短路)
- 非常可乐(bfs)
- 非常可乐(BFS)
- 非常可乐(BFS)
- hdu1495 非常可乐(bfs)
- hud1495 非常可乐(bfs)
- J - 非常可乐 (BFS)
- HDU1495 非常可乐(BFS)
- hdu1495非常可乐(BFS)
- HDU_1495非常可乐(BFS)
- 非常可乐 (bfs)HDU
- Jobdu1457 非常可乐(BFS)
- 非常可乐题解(BFS)
- hdu 非常可乐(BFS)(模拟)
- HDOJ 1495 非常可乐 (bfs)
- hdu 1495 非常可乐(BFS)
- HDU 1495非常可乐(BFS)
- 虚函数表解析
- Unicode转UTF-8(安卓android)
- 自定义View强势来袭,用自定义View实现歌词显示控件上篇之实现歌词文件解析
- @Controller和@RestController的区别
- System V进程间通信
- 非常可乐(BFS和最短路)
- SIGPIPE 信号
- 百度2017暑期实习生编程钓鱼比赛
- 文章标题
- Jetty的启动和关闭
- 设计模式之装饰者模式
- 7、Spring MVC 之 处理异步请求
- Centos7.2安装Saltstack
- Spring缓存机制的理解