过河问题详解

项目github地址:bitcarmanlee easy-algorithm-interview-and-practice
欢迎大家star,留言,一起学习进步

1.问题描述

在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边。如果不借助手电筒的话,大家是无论如何也不敢过桥去的。不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过。如果各自单独过桥的话,N人所需要的时间已知;而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间。问题是,如何设计一个方案,让这N人尽快过桥。

或许还有类似的问题,问题的描述可能不尽完全相同,但是大致的思路是一致的。

2.解法

对于一个规模比较大的问题,我们或许可以从小问题开始尝试来解决。
假设N个人过桥所需要的时间保存在一个数组nums中,nums经过排序由小到大,即过桥时间由快到慢,假设时间分别为abcdefg,a<b<c<d<e<f<g。
N=1时,过桥的时间为a
N=2时,过桥所有的时间为b
N=3时,过桥所需要的时间为a+b+c(ab先过去,所需时间为b,a再回来,所需时间为a,然后ac在过去,所需时间为c)
N=4时,此时两种方案有:
方案1:让a带最慢d先过去,然后a回来,再带次慢的c过去,a再回来,最后ab一起过去。
此方案所需要的时间为d+a+c+a+b=2a+b+c+d
方案2:先让最快的两个人ab过去,然后a回来,再让最慢的两个人过去,b回来,最后ab一起过去。此方案所需要的时间为b+a+d+b+b=a+3b+d
具体采取哪种方案,只需要比较方案1与方案2哪个更小即可。

3.代码实现

import java.util.Arrays;
import java.util.Scanner;

/**
 * Created by wanglei on 19/4/13.
 */
public class CrossRiver {

    public static int time = 0;

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] nums = new int[n];
        for (int j = 0; j < n; j++) {
            nums[j] = in.nextInt();
        }
        Arrays.sort(nums);
        cross(nums);
        System.out.println("time is: " + time);
    }

    // method1: ad过去(d), a回来(a),ac过去(c),a回来(a), ab过去(b) all time: 2a+b+c+d
    // method2: ab过去(b), a回来(a), cd过去(d),b回来(b),ab过去(b) all time: a+3b+d
    public static void cross(int[] nums) {
        if (nums.length == 1) {
            time += nums[0];
            return;
        }
        if (nums.length == 2) {
            time += nums[1];
            return;
        }
        if (nums.length == 3) {
            time += nums[0] + nums[1] + nums[2];
            return;
        }
        if (nums.length > 3) {
            if (nums[0] + nums[nums.length - 2] < 2 * nums[1]) {
                time += 2 * nums[0] + nums[nums.length - 2] + nums[nums.length - 1];
            } else {
                time += nums[0] + 2 * nums[1] + nums[nums.length - 1];
            }
            int[] tmp = Arrays.copyOfRange(nums, 0, nums.length - 2);
            cross(tmp);
        }
    }
}

假设输入的第一行为4,表示有4个人。第二行输入的为10 2 5 1,表示4个人过桥所需要的时间。最后的结果为17。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
农夫过河问题是一个经典的人工智能问题,可以用来介绍搜索算法。问题描述如下: 一个农夫带着一只狼、一只羊和一筐菜过河,只有一条小船,小船最多只能装下农夫和另外一只动物或者一筐菜。当农夫不在场时,狼会吃羊,羊会吃菜。请问农夫如何能够安全地把这三样东西都带过河? 下面是使用Matlab实现的代码: ```matlab % 农夫过河问题 % 1表示农夫、2表示狼、3表示羊、4表示菜 % 初始状态为[1,2,3,4,0],目标状态为[0,0,0,0,1] % 状态表示为[a,b,c,d,e],其中a,b,c,d表示四个置上的状态,e表示小船的置 % 0表示该置上无人或无物 function main() start = [1,2,3,4,0]; goal = [0,0,0,0,1]; path = bfs(start, goal); if isempty(path) disp('无解'); else disp('解为:'); disp(path); end end function path = bfs(start, goal) queue = [start, 0]; visited = [start]; path = []; while ~isempty(queue) node = queue(1, :); queue(1, :) = []; if isequal(node(1:5), goal) path = [node(6); path]; while node(6) ~= 0 node = visited(node(6), :); path = [node(6); path]; end return; end for i = 1:4 if node(5) == 0 && node(i) == 1 next = node; next(i) = 0; next(5) = 1; if ~ismember(next, visited, 'rows') queue = [queue; next, size(visited, 1) + 1]; visited = [visited; next]; end elseif node(5) == 1 && node(i) == 0 next = node; next(i) = 1; next(5) = 0; if ~ismember(next(1:5), visited, 'rows') && is_valid(next) queue = [queue; next, size(visited, 1) + 1]; visited = [visited; next(1:5)]; end elseif node(5) == 0 && node(i) ~= 1 && node(i) ~= 0 next = node; next(i) = 0; next(5) = 1; if ~ismember(next(1:5), visited, 'rows') && is_valid(next) queue = [queue; next, size(visited, 1) + 1]; visited = [visited; next(1:5)]; end elseif node(5) == 1 && node(i) ~= 1 && node(i) ~= 0 next = node; next(i) = 1; next(5) = 0; if ~ismember(next(1:5), visited, 'rows') && is_valid(next) queue = [queue; next, size(visited, 1) + 1]; visited = [visited; next(1:5)]; end end end end end function valid = is_valid(node) if node(2) == 3 && node(3) == 4 && node(5) == 0 valid = false; elseif node(2) == 0 && node(3) == 4 && node(5) == 1 valid = false; elseif node(2) == 3 && node(3) == 0 && node(5) == 1 valid = false; elseif node(2) == 0 && node(3) == 0 && node(5) == 0 valid = false; else valid = true; end end ``` 其中,bfs函数是使用宽搜算法实现的,is_valid函数用来判断当前状态是否合法。程序运行后会输出解的路径,如果无解则会输出“无解”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值