zoukankan      html  css  js  c++  java
  • java实现 n人过桥问题

    java实现 n人过桥问题

    【问题描述】

    n个人要晚上过桥,在任何时候最多两个人一组过桥,每组要有一只手电筒。在这n个人中只有一个手电筒能用,求这些人过桥所用的最短时间。

    【输入】

    输入的第一行给出n,接下来的n行给出每个人的过桥时间
    例如: 5 1 2 3 4 5
    

    【输出】

    输出的第一行给出所有n个人过桥的总的秒数,接下来的若干行给出实现策略。每行包括一个或两个整数,表示组成一组过桥的一个或两个人,以所用的时间标识。
    5
    1 2 3 4 5
    去: 1, 2
    回: 1
    去: 4, 5
    回: 2
    去: 1, 3
    回: 1
    去: 1, 2
    最短时间: 16
    

    【问题分析】

    当看到求最短、最长、最多、最少等字样的时候,大概率会是动态规划或者贪心算法的问题。n人过桥问题是比较典型的贪心算法,由于一次过桥最多两人且手电筒需要往返传递,因此以两个成员过桥为一个分析单位,计算过桥时间。首先按过桥时间顺序从小到大排序,nums[1]为最小,nums[n]为最大。

    我们可以这么思考贪心算法的问题:将贪心问题分为多个子问题,这些子问题相互之间没有关联(动态规划的每一个子问题都会相互关联,这是与贪心算法的主要区别),且每个子问题的状态都是独立的。那么我们可以这样思考n人过桥问题:每个子问题所求的都是过去两人所花费的最短时间,且手电要回到起始点。贪心就贪在每次我都想让两个最费时的人过去。

    基于上述思想,问题简化为如何求得最费时的两个人过去所花费的最短时间呢?这里有点拗口哈。有两种方案:

    方案一:用最快的成员nums[1]传递手电筒帮助最慢的nums[n]和nums[n-1]过桥,易知来回所用的时间为2*nums[1]+nums[n]+nums[n-1]。

    方案二:用最快的成员nums[1]和次快的成员nums[2]传递手电筒帮助最慢的nums[n]和nums[n-1]过桥,具体方案如下:

    第一步:nums[1]和nums[2]到对岸,所用时间为nums[2];
    
    第二步:nums[1]返回,将手电筒给最慢的nums[n]和nums[n-1],并且nums[n]和nums[n-1]到对岸后将手电筒交给nums[2],所用时间为:nums[1]+nums[n];
    
    第三步:nums[2]返回,所用时间为nums[2];
    
    综合起来方案二所用的总时间为2*nums[2]+nums[n]+nums[1]。
    
    

    最后,不论是动态规划还是贪心算法,都需要考虑边界条件

    显然,这里的边界条件是: 最后尚未过桥的人可能有3人或者2人,如果是3人,则最少过桥时间为nums[1]+nums[2]+nums[3],如果是2人,则是nums[1]+nums[2]。下面是算法实现:

    public class Test {
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt(); // 读取人数
            int[] nums = new int[n+1];
            Arrays.sort(nums);
            for (int i = 1; i <= n; i++) {
                nums[i] = sc.nextInt();
            }
            int result = 0;
            int stay = n;
            while(stay > 3){
                if(nums[1] + nums[stay-1] > 2*nums[2]) {
                    // 第二种方案
                    System.out.println("去: " + nums[1] + ", " + nums[2]);
                    System.out.println("回: " + nums[1]);
                    System.out.println("去: " + nums[stay-1] + ", " + nums[stay]);
                    System.out.println("回: " + nums[2]);
                    result += 2*nums[2] + nums[stay] + nums[1];
                } else {
                    // 第一种方案
                    System.out.println("去: " + nums[1] + ", " + nums[stay]);
                    System.out.println("回: " + nums[1]);
                    System.out.println("去: " + nums[1] + ", " + nums[stay-1]);
                    System.out.println("去: " + nums[1]);
                    result += 2*nums[1] + nums[stay] + nums[stay-1];
                }
                stay -= 2;
            }
    
            if (stay == 3){
                System.out.println("去: " + nums[1] + ", " + nums[3]);
                System.out.println("回: " + nums[1]);
                System.out.println("去: " + nums[1] + ", " + nums[2]);
                result += (nums[1] + nums[2] + nums[3]);
            } else {
                System.out.println("去:" + nums[1] + ", " + nums[2]);
                result += (nums[2]);
            }
            System.out.println("最短时间: " + result);
        }
    }
    

    当然,如果不需要显示来回的过程,只需要把打印语句去掉即可,这样使代码变得简便:

    public class Test {
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt(); // 读取人数
            int[] nums = new int[n+1];
            Arrays.sort(nums);
            for (int i = 1; i <= n; i++) {
                nums[i] = sc.nextInt();
            }
            int result = 0;
            int stay = n;
            while(stay > 3){
                if(nums[1] + nums[stay-1] > 2*nums[2]) {
                    // 第二种方案
                    result += 2*nums[2] + nums[stay] + nums[1];
                } else {
                    // 第一种方案
                    result += 2*nums[1] + nums[stay] + nums[stay-1];
                }
                stay -= 2;
            }
            if (stay == 3){
                result += (nums[1] + nums[2] + nums[3]);
            } else {
                result += (nums[2]);
            }
            System.out.println("最短时间: " + result);
        }
    }
    
    
  • 相关阅读:
    element-ui+mongodb+express项目的实现(含源代码)
    Mybatis之逆向工程的文件和方法解析
    Mybatis之逆向工程的配置和实操
    ### The error may exist in com/online/dao/BlogMapper.java (best guess)
    ### Error opening session. Cause: java.lang.NullPointerException
    mongodb下载安装和基本操作
    SSM框架的具体搭建配置
    JSON字符串多了一个等号
    JSON使用变量值作为键名
    Ajax中文乱码解决方法
  • 原文地址:https://www.cnblogs.com/tian874540961/p/12390620.html
Copyright © 2011-2022 走看看