羊、狼、农夫过河
问题描述
羊、狼、农夫都在岸边,当羊的数量小于狼的数量时,狼会攻击羊,农夫则会损失羊。农夫有一艘容量固定的船,能够承载固定数量的动物。
要求求出不损失羊情况下将全部羊和狼运到对岸需要的最小次数。
只计算农夫去对岸的次数,回程时农夫不会运送羊和狼。
备注:农夫在或农夫离开后羊的数量大于狼的数量时狼不会攻击羊。
农夫自身不占用船的容量。
输入描述
第一行输入为M,N,X, 分别代表羊的数量,狼的数量,小船的容量。
输出描述
输出不损失羊情况下将全部羊和狼运到对岸需要的最小次数(若无法满足条件则输出0)。
示例
输入
5 3 3
输出
3
说明
第一次两只狼
第二次三只羊
第三次两只羊和一只狼
解题思路
需要渡河次数最小,则需要每次尽可能运输数量最大;
- M + N < = X M + N <= X M+N<=X 时一次运输完成;
- M < = X M <= X M<=X时
当 N < M + X N < M + X N<M+X时:
1. 3 X > M + N > 2 X 3X > M + N > 2X 3X>M+N>2X,首次渡河时先运输M
, 第二次运输狼数量M - 1
, 第三次将剩余狼全部运输;
2. M + N < = 2 X M + N <= 2X M+N<=2X,首次满载运输狼,第二次所有运输;
当 N > = M + X N >= M + X N>=M+X时:
1. 首次全狼过河,岸边狼数量大于等于羊数量,羊被攻击;
2. 首次全羊过河,狼过河时必定需要拆分为两次,由于 N > = M + X N >= M + X N>=M+X,则至少需要输送M
,对岸羊被攻击;
- 当 M > X M > X M>X时
N > = M N >= M N>=M:首次运输存在两种情况, 狼比羊少(运输时岸边羊直接死亡)、全狼(第二次运输是为保证对岸羊比狼多, 岸边羊会少于狼数量)
N = M − 1 N = M - 1 N=M−1:首次狼比羊少(岸边羊数量不大于狼), 全狼(第二次运输是为保证对岸羊比狼多, 岸边羊会不大于狼数量)
N < M − 1 N < M - 1 N<M−1
N = M − 2 N = M - 2 N=M−2
- 船容量为单数: M1 + N1 = X, M1 = N1 + 1, 后续Mi = Ni运输, 直至M1 + N1 <= X;
- 船容量为双数: M1 + N1 + 1 = X, 2M1 = X运输, 后续满负载M1 = N1运输
N < M − 2 N < M - 2 N<M−2
- 船容量为单数, 先满容量运输 M1 = N1 + 1, 后续运输时先M1 = N1 + 1, 后M1 = N1 - 1满容量运行;
- 船容量为双数, 满容量运输 M1 = N1 + 2, 后续狼羊同等数量运输;
代码示例
/**
* 狼羊过河最小过河次数
* @param m 羊数量
* @param n 狼数量
* @param x 船容量
* @return 最小过河次数
*/
public int wolfSheep(int m, int n, int x) {
if((m + n) <= x) {
return 1;
}
if(m <= x) {
if(n >= x + m) {
return 0;
}
return (m + n - 1) / x + 1;
}
if(n >= m - 1) {
return 0;
}
if(n == m - 2) {
if((x & 0b1) == 0) {
return (m + n) / x + 1;
} else {
return (m + n - 3) / (x - 1) + 1;
}
}
return (m + n - 1) / x + 1;
}