Problem 2188 过河I
Accept: 52 Submit: 131
Time Limit: 3000 mSec Memory Limit : 32768 KB
Problem Description
一天,小明需要把x只羊和y只狼运输到河对面。船可以容纳n只动物和小明。每次小明划船时,都必须至少有一只动物来陪他,不然他会感到厌倦,不安。不论是船上还是岸上,狼的数量如果超过羊,狼就会把羊吃掉。小明需要把所有动物送到对面,且没有羊被吃掉,最少需要多少次他才可以穿过这条河?
Input
有多组数据,每组第一行输入3个整数想x, y, n (0≤ x, y,n ≤ 200)
Output
如果可以把所有动物都送过河,且没有羊死亡,则输出一个整数:最少的次数。 否则输出 -1 .
Sample Input
3 3 233 33 3
Sample Output
11-1
Hint
第一个样例
次数 船 方向 左岸 右岸(狼 羊)
0: 0 0 3 3 0 0
1: 2 0 > 1 3 2 0
2: 1 0 < 2 3 1 0
3: 2 0 > 0 3 3 0
4: 1 0 < 1 3 2 0
5: 0 2 > 1 1 2 2
6: 1 1 < 2 2 1 1
7: 0 2 > 2 0 1 3
8: 1 0 < 3 0 0 3
9: 2 0 > 1 0 2 3
10: 1 0 < 2 0 1 3
11: 2 0 > 0 0 3 3
Source
FOJ有奖月赛-2015年03月
/*
题目:2188 过河I
链接:http://acm.fzu.edu.cn/problem.php?pid=2188
题意:小明需要把x只羊和y只狼运输到河对面。船可以容纳n只动物和小明。每次小明划船时,都
必须至少有一只动物来陪他。不论是船上还是岸上,狼的数量如果超过羊,狼就会把羊吃掉。
问小明需要把所有动物送到对面,且没有羊被吃掉,最少需要多少次他才可以穿过这条河。
思路:BFS(广度优先搜索)。记录两岸羊跟狼的数量以及步骤数。没有特殊技巧,就是细节比较
多,细心点就好了,详情见代码。
*/
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define inf 1000000000
#define LL long long
#define N 210 //数组大小
bool vis[2][N][N];
int x, y, n;
struct node{
int sw, sh, ew, eh, step;//sw 起始一端狼的数量,sh 起始一端羊的数量,ew 终点一端狼的数量,eh 终点一端羊的数量, step 步骤数
node(){}
node(int sw, int sh, int ew, int eh, int step) :sw(sw), sh(sh), ew(ew), eh(eh), step(step){}
};
int bfs()
{
memset(vis, false, sizeof vis);
vis[0][y][x] = true;
queue<node> Q;
Q.push(node(y, x, 0, 0, 0));//入队
while (!Q.empty())
{
node now = Q.front();//取队首元素
Q.pop();//出队
if (now.ew == y && now.eh == x) return now.step;//到达目标,返回步骤数
int k = (now.step % 2) == 0 ? 1 : -1;//k = 1, 从起始一端到终点一端, k = -1, 从终点一端到起始一端
for (int i = n; i >= 0; i--)//i,枚举运输狼的数量
{
if (now.sw - i * k < 0) continue;//判断不合法情况
if (now.sw - i * k > y) continue;
if (now.ew + i * k < 0) continue;
if (now.ew + i * k > y) continue;
for (int j = 0; j <= n - i; j == 0 ? (i == 0 ? j = i + 1 : j = i) : j++)//j,枚举运输羊的数量
{//唯一一种i > j,就是当j = 0的时候,其余情况必须j >= i。
if (i + j == 0) continue;//运输过程中必须要有动物
if (now.sh - j * k < 0) continue;//判断不合法情况
if (now.sh - j * k > x) continue;
if (now.eh + j * k < 0) continue;
if (now.eh + j * k > x) continue;
if (now.sw - i * k > now.sh - j * k && now.sh - j * k != 0) continue;//起始一端狼的数量大于羊的数量且羊的数量不为零的时候不合法
if (now.ew + i * k > now.eh + j * k && now.eh + j * k != 0) continue;//终点一端狼的数量大于羊的数量且羊的数量不为零的时候不合法
if (vis[(now.step + 1) % 2][now.sw - i * k][now.sh - j * k]) continue;//该情况已经出现过不合法
vis[(now.step + 1) % 2][now.sw - i * k][now.sh - j * k] = true;
Q.push(node(now.sw - i * k, now.sh - j * k, now.ew + i * k, now.eh + j * k, now.step + 1));//合法,入队
}
}
}
return -1;
}
int slove(int num)
{
int res = 0;
while (num > n - 1)
{
if (num == n)
res++, num = 0;
else res += 2, num -= n - 1;
}
if (num > 0) res++;
return res;
}
int main()
{
while (~scanf("%d%d%d", &x, &y, &n))
{
if (x == 0 && y == 0) printf("0\n");
else if (n == 0) printf("-1\n");
else if (n == 1)
{
if (x + y == 1) printf("1\n");
else printf("-1\n");
}
else if (y == 0)
printf("%d\n", slove(x));
else if (x == 0)
printf("%d\n", slove(y));
else if (y > x) printf("-1\n");
else printf("%d\n", bfs());
}
return 0;
}