1、题目描述
羊、狼、农夫都在岸边,当羊的数量小于狼的数量时,狼会攻击羊,农夫则会损失羊。农夫有一艘容量固定的船,能够承载固定数量的动物。
要求求出不损失羊情况下将全部羊和狼运到对岸需要的最小次数。只计算农夫去对岸的次数,回程时农夫不会运送羊和狼。
备注:农夫在或农夫离开后羊的数量大于狼的数量时狼不会攻击羊
2、输入描述
第一行输入为M,N,X, 分别代表羊的数量,狼的数量,小船的容量。
3、输出描述
输出不损失羊情况下将全部羊和狼运到对岸需要的最小次数(若无法满足条件则输出0)。
4、题解
羊的数量与狼的数量小于等于船的数量时,则一次即可运完
羊的数量与狼的数量单独都小于船的容量时,两次即可运完,一次全部运羊,一次全部运狼
其他场景下:
羊的数量大于狼的数量,狼才不会攻击羊,要确保两岸的羊都不会被狼攻击,那么羊与狼的数量差不得小于2(根据备注条件自己好好思考理解下),根据船的容量的奇偶分别处理
偶数容量:
首次运输尽可能多运羊,保证船满载同时确保两岸的羊数量不小于狼,之后对半运输即可,当狼的数量不足半船的时候,全部运完狼,剩余的运羊,若没有狼时则全部运羊
奇数容量:
首次运输,需要运输羊的数量多于狼,同时确保两岸羊的数量不小于狼,如果本岸的羊-狼>=2,那么可以运输X/2+1羊,剩余运狼,如果本岸的羊-狼==1,则运送相同数量的羊和狼,当狼不足半船则全部运完,当没有狼时则仅运羊
温馨提示!!!
华为OD机试考试官方会对考生代码查重,od机试因为有题库所以有很大的概率会抽到原题,如果碰到了题库中的原题,千万不要直接使用题解中的代码,一定要做些修改,比如代码中的变量名,除此之外,代码的组织结构和逻辑也要进行一些改变,所以在日常的刷题中,要提前编写好属于自己的代码。
代码如下:
// 总运输次数
private static int times = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] param = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
// 羊的数量
int M = param[0];
// 狼的数量
int N = param[1];
// 船的容量
int X = param[2];
// 羊+狼 <= 船的容量,则一次运完
if (M + N <= X) {
System.out.println(1);
return;
}
// 两次即可运完 一次全部运羊+一次全部运狼
if (M <= X && N <= X) {
System.out.println(2);
return;
}
// 羊与狼的数量差小于2时,会损失羊
if (M - N < 2) {
System.out.println(0);
return;
}
// 船的容量=偶数
if (X % 2 == 0) {
boolean first = true;
while (M >= X / 2 && N >= X / 2) {
// 首次运输,需要运输羊的数量多于狼
if (first) {
// 本岸的羊大于狼时
if (M - X / 2 - 1 > N - X / 2 + 1) {
M = M - (X / 2 + 1);
N = N - (X / 2 - 1);
first = false;
} else {
// 本岸的羊等于狼,则运输半船羊,半船-1只狼(首次确保羊多于狼)
M = M - (X / 2);
N = N - (X / 2 - 1);
first = false;
}
} else {
// 非首次运输,对半即可
M = M - (X / 2);
N = N - (X / 2);
}
times++;
}
// 船的容量=奇数
} else {
boolean flag = true;
boolean first = true;
while (M >= X / 2 && N >= X / 2) {
// 首次运输
if (first) {
M = M - (X / 2 + 1);
N = N - (X / 2);
first = false;
} else {
/**
* 如果本岸羊比狼多出两只及以上
* 则可以先运X/2+1只羊、X/2只狼
*/
if (M > N + 1) {
if (flag) {
M = M - (X / 2 + 1);
N = N - (X / 2);
flag = false;
} else {
M = M - (X / 2);
N = N - (X / 2 + 1);
flag = true;
}
} else {
// 运输相同只羊和狼
if (M + N > X) {
M = M - (X / 2);
N = N - (X / 2);
} else {
M = M - (X / 2 + 1);
N = N - (X / 2);
}
}
}
times++;
}
}
// 羊与狼的数量没有剩余,则运输完成
if (M == 0 && N == 0) {
System.out.println(times);
return;
}
// 狼+羊 <= 船的容量,则一次运完
if (M + N <= X) {
M = 0;
N = 0;
} else {
// 当羊+狼>船,狼不足半船时,将狼全部运完,剩余运羊
M = M - (X - N);
}
times++;
// 运输剩余的羊
while (M > 0) {
M -= X;
times++;
}
// 输出运输次数
System.out.println(times);
}
本题也可以使用深度搜索的方法解决,根据自己的情况,选择一种方法掌握即可,应对考试尽可能提高效率。
代码如下
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] param = Arrays.stream(sc.nextLine().split(" "))
.mapToInt(Integer::parseInt).toArray();
// 羊的数量
int M = param[0];
// 狼的数量
int N = param[1];
// 船的容量
int X = param[2];
int times = trans(M, N, X, 0, 0, 0);
// 输出运输次数
System.out.println(times);
}
/**
* @param m 本岸羊的数量
* @param n 本岸狼的数量
* @param x 船的容量
* @param m1 对岸羊的数量
* @param n1 对岸狼的数量
* @param count 当前运输次数
* @return
*/
private static int trans (int m, int n, int x, int m1, int n1, int count) {
// 羊+狼 <= 船的容量,则一次运完
if (m + n <= x) {
return count + 1;
}else if (m <= x && n <= x) {
// 两次即可运完 一次全部运羊+一次全部运狼
return count + 2;
}else if (count == 0 && m-n < 2) {
return 0;
}
for (int i=x; i>0; i--) {
for (int j=i; j>=0; j--) {
if (j > m || (i-j) > n) {
continue;
}
// 本岸剩余羊的数量
int m2 = m - j;
// 本岸剩余狼的数量
int n2 = n - (i-j);
// 对岸羊的数量
int m3 = m1 + j;
// 对岸狼的数量
int n3 = n1 + (i-j);
// 两岸的羊的数量都需要大于狼的数量
if ((m2 > n2 || m2 == 0 || n2 == 0) && (m3 > n3 || m3 == 0 || n3 == 0)) {
int result = trans(m2, n2, x, m3, n3, count+1);
if (result > 0) {
return result;
}
}
}
}
return 0;
}
执行结果如下: