FZU(2188):狼羊过河问题,状态转移,BFS求解
2015-03-23 13:14
330 查看
题目连接:http://acm.fzu.edu.cn/problem.php?pid=2188
意思:中文题目,就是给定狼羊的数目,求最小运输量把狼和羊全部送到对岸,条件是,岸上和船上的羊不能少于狼的数目,且每次渡船至少有一只动物。无解则输出-1。
只要认真分析,还是能够想到状态转移方法的。
假设左岸分别有x,y只羊和狼,右岸分别有羊和狼m,n只,假设从左岸分别把羊狼转移p,q只到右岸,则必须满足一下条件:
x-p不为0时,x-p>=y-q;
m+p不为0时,m+p>=n+q;
p不为0时,p>=q;
这里需要注意的是,当x-p或m+q或p为0时,需要特殊处理,此时,狼可以为任意值(必须客观)不必大于羊的数目。
从右岸到左岸的思想差不多。
分析到此。
代码:
刚开始用BFS交,TLE了,然后改写双BFS,结果却是RE,仔细一看,居然是两次都交错题目了,真是汗颜啊!!!!
不过,这题用BFS和双BFS差距还是蛮大的,一个70ms+,一个达到了900ms+。
单向BFS:
双向BFS:
意思:中文题目,就是给定狼羊的数目,求最小运输量把狼和羊全部送到对岸,条件是,岸上和船上的羊不能少于狼的数目,且每次渡船至少有一只动物。无解则输出-1。
只要认真分析,还是能够想到状态转移方法的。
假设左岸分别有x,y只羊和狼,右岸分别有羊和狼m,n只,假设从左岸分别把羊狼转移p,q只到右岸,则必须满足一下条件:
x-p不为0时,x-p>=y-q;
m+p不为0时,m+p>=n+q;
p不为0时,p>=q;
这里需要注意的是,当x-p或m+q或p为0时,需要特殊处理,此时,狼可以为任意值(必须客观)不必大于羊的数目。
从右岸到左岸的思想差不多。
分析到此。
代码:
刚开始用BFS交,TLE了,然后改写双BFS,结果却是RE,仔细一看,居然是两次都交错题目了,真是汗颜啊!!!!
不过,这题用BFS和双BFS差距还是蛮大的,一个70ms+,一个达到了900ms+。
单向BFS:
#include<iostream> #include<cstdio> #include<sstream> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<queue> #include<vector> #include<map> #include<string> #define LL __int64 #define INF 0xfffffff using namespace std; struct state{ int x,y;//左岸羊狼的数目 int m,n;//右岸羊狼的数目 int step;//转移步数 }; int vis[220][220][2];//左岸状态标志,为什么是2呢?vis[x][y]有两种不同的值 //可能是从右岸转移到左岸后的x,y,也可能是从右岸转移到左岸 //后的x,y,这两者是不一样的 int X,Y,N; void bfs(){ queue<state> Q; Q.push((state){X,Y,0,0,0}); vis[X][Y][0]=vis[X][Y][1]=1; while(!Q.empty()){ state tp=Q.front(); if(!tp.x && !tp.y){ cout<<tp.step<<endl; return; } Q.pop(); if(tp.step & 1){//从右岸到左岸 for(int p=0;p<=min(N,tp.m);p++)//下面需要注意的是羊为0时,狼的数目的处理 for(int q=0;!p && (q<=min(tp.n,N)) || p && q<=p && (p+q)<=min(tp.m+tp.n,N);q++){ if(p+q==0) continue; int tx=tp.x+p,ty=tp.y+q,tm=tp.m-p,tn=tp.n-q; //下面也得注意羊的数目为0时,狼的数目的处理 if(tm<0 || tn<0 || tm && tm<tn || tx&&tx<ty) continue; if(!vis[tx][ty][1]){ vis[tx][ty][1]=1; Q.push((state){tx,ty,tm,tn,tp.step+1}); } } } else{//从左岸到右岸 for(int p=0;p<=min(N,tp.x);p++) for(int q=0;!p && (q<=min(N,tp.y)) || p && q<=p &&(p+q)<=min(N,tp.x+tp.y);q++){ if(p+q==0) continue; int tx=tp.x-p,ty=tp.y-q,tm=tp.m+p,tn=tp.n+q; if(tx<0 || ty<0 || tx && tx<ty || tm&&tm<tn) continue; if(!vis[tx][ty][0]){ vis[tx][ty][0]=1; Q.push((state){tx,ty,tm,tn,tp.step+1}); } } } } cout<<-1<<endl; } int main(){ //freopen("C:\\Documents and Settings\\All Users\\桌面\\in.txt","r",stdin); while(cin>>X) { cin>>Y>>N; memset(vis,0,sizeof(vis)); bfs(); } return 0; }
双向BFS:
#include<iostream> #include<cstdio> #include<sstream> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<queue> #include<vector> #include<map> #include<string> #define LL __int64 #define INF 0xfffffff using namespace std; struct state{ int x,y; int m,n; int step; }; int vis[220][220][2]; int vis2[220][220][2]; int X,Y,N; //双向BFS的代码看起来比较长,但也仅仅是BFS的基础上再Ctrl+C而已 //需要两个vis数组分别表示前后的访问状态,主要是在BFS的基础上处理相遇的情况 void bfs(){ queue<state> Q,QQ; Q.push((state){X,Y,0,0,0}); QQ.push((state){0,0,X,Y,0}); vis2[0][0][0]=vis2[0][0][1]=1; vis[X][Y][0]=vis[X][Y][1]=1; int deep=0; while(!Q.empty() || !QQ.empty()){ while(!Q.empty()){ state tp=Q.front(); if(tp.step!=deep) break; Q.pop(); if(tp.step & 1){ for(int p=0;p<=min(N,tp.m);p++) for(int q=0;!p && (q<=min(tp.n,N)) || p && q<=p && (p+q)<=min(tp.m+tp.n,N);q++){ if(p+q==0) continue; int tx=tp.x+p,ty=tp.y+q,tm=tp.m-p,tn=tp.n-q; if(tm<0 || tn<0 || tm && tm<tn || tx&&tx<ty) continue; if(vis2[tx][ty][0]){cout<<(deep)*2+1<<endl;return;}//相遇时两个状态必须是连贯的 if(!vis[tx][ty][1]){ vis[tx][ty][1]=1; Q.push((state){tx,ty,tm,tn,tp.step+1}); } } } else{ for(int p=0;p<=min(N,tp.x);p++) for(int q=0;!p && (q<=min(N,tp.y)) || p && q<=p &&(p+q)<=min(N,tp.x+tp.y);q++){ if(p+q==0) continue; int tx=tp.x-p,ty=tp.y-q,tm=tp.m+p,tn=tp.n+q; if(tx<0 || ty<0 || tx && tx<ty || tm&&tm<tn) continue; if(vis2[tx][ty][1]){cout<<deep*2+1<<endl;return;} if(!vis[tx][ty][0]){ vis[tx][ty][0]=1; Q.push((state){tx,ty,tm,tn,tp.step+1}); } } } } while(!QQ.empty()){ state tp=QQ.front(); if(tp.step!=deep) break; QQ.pop(); if(tp.step%2==0){//这里需要和上面反过来处理,可以仔细想想 for(int p=0;p<=min(N,tp.m);p++) for(int q=0;!p && (q<=min(tp.n,N)) || p && q<=p && (p+q)<=min(tp.m+tp.n,N);q++){ if(p+q==0) continue; int tx=tp.x+p,ty=tp.y+q,tm=tp.m-p,tn=tp.n-q; if(tm<0 || tn<0 || tm && tm<tn || tx&&tx<ty) continue; if(vis[tx][ty][1]){cout<<(1+deep)*2<<endl;return;} if(!vis2[tx][ty][0]){ vis2[tx][ty][0]=1; QQ.push((state){tx,ty,tm,tn,tp.step+1}); } } } else{ for(int p=0;p<=min(N,tp.x);p++) for(int q=0;!p && (q<=min(N,tp.y)) || p && q<=p &&(p+q)<=min(N,tp.x+tp.y);q++){ if(p+q==0) continue; int tx=tp.x-p,ty=tp.y-q,tm=tp.m+p,tn=tp.n+q; if(tx<0 || ty<0 || tx && tx<ty || tm&&tm<tn) continue; if(vis[tx][ty][0]){cout<<(deep+1)*2<<endl;return;} if(!vis2[tx][ty][1]){ vis2[tx][ty][1]=1; QQ.push((state){tx,ty,tm,tn,tp.step+1}); } } } } deep++; } cout<<-1<<endl; } int main(){ //freopen("C:\\Documents and Settings\\All Users\\桌面\\in.txt","r",stdin); while(cin>>X) { cin>>Y>>N; memset(vis2,0,sizeof(vis2)); memset(vis,0,sizeof(vis)); bfs(); } return 0; }
相关文章推荐
- FZOJ 2188 过河I (确定状态+BFS)
- FZU - 2188过河I【BFS】
- (BFS)FZU.Problem 2188 过河I
- FZU--2188--过河(bfs暴力条件判断)
- FZU--2188--过河(bfs暴力条件判断)
- FZU 2028 时空门问题(bfs+vector)
- 独立岛问题的BFS,DFS求解
- FZU - 1205 小鼠迷宫问题 (bfs+dfs)
- 模拟求解迷宫问题(DFS+BFS)
- FZU 2150 稍复杂的BFS的问题
- [置顶] 模拟求解迷宫问题(DFS+BFS)
- 利用BFS、队列求解迷宫问题
- 第十二周--利用遍历思想求解图问题(BFS)
- 经典算法<一>迷宫问题 3.多条路径 BFS求解 C++实现
- FUZoj 过河I 2188 (bfs多条件判断) 好题
- FZU--2188(BFS+多条件判断,这题超好)
- 用BFS和DFS解决圆盘状态搜索问题
- hdu 4504 dp问题 转化能力不够 对状态的转移也是不够
- poj 1077 Eight 八数码问题( 康拓展开+BFS状态压缩)
- fzu 2188 过河I