题意:
左岸有x只羊,y只狼,船每次可以载p只动物,狼比羊数量超过q只就会出事(即x+q<y),农夫一开始在左岸,有农夫的地方不会出事,问不出事的前提下把所有羊运到右岸的最少渡河次数(单程,去和回来都要算)
思路:
一开始以为是思维题,但是看到第三个样例发现太难想了,而且数据很小,所以考虑爆搜。设置一个状态 S [ x , y , f ] S[x,y,f] S[x,y,f]表示左岸有x只羊,y只狼,农夫在哪(0表示在左岸,1表示右岸),存储到达这个状态的渡河次数,这样就把一个局面用三个状态描述下来了。考虑用bfs,转移的话就是从当前状态枚举船上羊的个数i和狼的个数j,剩下p-i-j的位置留空。还可以设置一个vis数组来防止重复走过一些状态,时间复杂度最坏是O(n^4),能过。
code:
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn=105;
int x,y,p,q;//羊 狼 运输数量 差值
struct S{
int x,y,f;
int tm;
};
queue<S> s;
bool vis[maxn][maxn][2];
void pt(S x){
printf("%d %d %s %d\n",x.x,x.y,(x.f)?"右岸":"左岸",x.tm);
}
int main(){
cin>>x>>y>>p>>q;
s.push((S){x,y,0,0});
vis[x][y][0]=true;
while(!s.empty() && s.front().x!=0){
S now=s.front();
// pt(now);
s.pop();
for(int i=0;i<=p;i++)
for(int j=0;j<=p-i;j++){//船上i只羊j只狼p-i-j留空
if(!now.f){//左岸->右岸
if(i>now.x || j>now.y)continue;//船上不符合条件
if(now.x-i!=0 && now.x-i+q<now.y-j)continue;//左岸不符合条件
if(vis[now.x-i][now.y-j][1])continue;
s.push((S){now.x-i,now.y-j,1,now.tm+1});
vis[now.x-i][now.y-j][1]=true;
}
else {//右岸->左岸
if(i>x-now.x || j>y-now.y)continue;//船上不符合条件
if(x-now.x-i!=0 && x-now.x-i+q<y-now.y-j)continue;//右岸不符合条件
if(vis[now.x+i][now.y+j][0])continue;
s.push((S){now.x+i,now.y+j,0,now.tm+1});
vis[now.x+i][now.y+j][0]=true;
}
}
}
if(!s.empty())cout<<s.front().tm;
else cout<<-1;
return 0;
}
/*
4 4 3 1
3 5 2 0
2 5 1 1
*/