题目描述:一个农夫带着m只羊,n只狼过河,农夫有一条可载x只羊/狼的船,农夫在时或者羊的数量大于狼时,狼不会攻击羊;农夫在不损失羊的情况下,运输几次可以完成运输?
备注:羊和狼只会被运送一次,返程不会携带。
输入描述: 输入参数为m,n,x; m为羊的数量,n为狼的数量,x为船的承载量
输出描述: 输出最少完成运输的次数,如无法在不损失羊的情况下完成运输,则返回-1
示例:
输入: 5 3 3
输出: 3
说明:详解:
第一次:2只狼
第二次:3只羊
第三次:2只羊,1只狼
思路:每次携带羊狼过河后,只要河岸两边羊的数量大于狼,或者只有一种动物,羊都不会损失,因此每次携带羊狼时候,我们需要保证确保该次携带是可行的,而且尽可能多带,这样运输次数才会最少,递归调用携带方法,直到所用狼和羊均运送完成。
用四个变量m,n,m1,n1分别记当前剩余羊的数量,狼的数量,以及对岸羊和狼的数量,用i和j分别记住每次携带羊和狼的数量。
public static int ship(int m, int n, int x, int m1, int n1, int count) {
if ((m + n) <= x) {
System.out.println("第" + (count + 1) + "次运送, " + (m) + " : " + (0));
return count + 1;
} else if ((m <= x) && (n <= x)) {
System.out.println("第" + (count + 1) + "次运送, " + (m) + " : " + (0));
System.out.println("第" + (count + 2) + "次运送, " + (0) + " : " + (n));
return count + 2;
} else if ((count == 0) && ((m - n) < 2)) {
//如果羊最多比狼多一只,则无法完成运送
return -1;
}
//每次尽量多携带
for (int onceCount = x; onceCount > 0; onceCount--) {
for (int i = onceCount; i >= 0; i--) {
//本次运送的量,大于实际的量,则跳过
if ((i > m) || ((onceCount - i) > n)) {
continue;
}
//确保本次运送后,羊的数量大于狼,若状态正确,则即可运输
int m2 = m - i;
int n2 = n - (onceCount - i);
int m3 = m1 + i;
int n3 = n1 + (onceCount - i);
if (((m2 > n2) || (m2 == 0) || (n2 == 0)) && ((m3 > n3) || (m3 == 0) || (n3 == 0))) {
System.out.println("第" + (count + 1) + "次运送, " + (i) + " : " + (onceCount - i));
//递归运送,若返回结果大于0,则表面该运送策略可行
int ship = ship(m2, n2, x, m3, n3, count + 1);
if (ship > 0) {
return ship;
}
}
}
}
return -1;
}
测试运行:
public class Test {
public static void main(String[] args) {
System.out.println("总运输次数:" + ship(5, 3, 3, 0, 0, 0));
}
}
运行结果:
第1次运送, 2 : 1
第2次运送, 3 : 0
第3次运送, 0 : 2
总运输次数:3