华为OD机试【羊、狼、农夫过河】(java)(100分)

文章介绍了通过算法解决农夫运羊过河问题,讨论了奇偶数船容量下的策略,包括如何保证羊安全和最小化运输次数。
摘要由CSDN通过智能技术生成

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;
}

执行结果如下:
在这里插入图片描述

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搬砖小夫子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值