2017完美世界研发部笔试题_取经

一、题目概述

师徒四人西天取经,途中必需跨过一座桥,四个人从桥的同一端出发,你得帮助他们到达另一端,天色很暗而他们只有一支手电筒,一次同时最多可以有两个人一起经过桥。而过桥的时候必须持有手电筒,所以就得有人把手电筒带来带去,来回桥两端。手电筒不能用丢的方式来传递,四个人的步行速度各不同,若两人同行则以较慢者的速度为准,大师兄需花1分钟过桥,二师兄需花2分钟过桥,三师兄需花5分钟过桥,师傅需花10分钟过桥。请问他们最短在多少分钟内过桥?()
A. 18
B. 17
C. 19
D. 16


二、思路

一开始直接想到,用最小的那个数来回跑,也就是大师兄来回跑,算出来是19,可是又想了下,如下:
1、大师兄和二师兄过桥,算二师兄的时间也就是2分钟
2、大师兄独自拿手电回来 1分钟
3、三师弟和师傅那手电过桥,算师傅的时间也就是10分钟
4、二师弟拿手电回来 2分钟
5、最后大师兄和二师弟过桥 2分钟
总共17分钟

这里写图片描述

虽然结果出来了,感觉有点不实在,这其中的规律是怎样的呢?有没有什么规律解决这类似的问题呢,比如只有三个人过桥呢?二师兄不过桥,结果又是什么呢?再比如,多一个人过桥呢?多了个白龙马过桥,白龙马过桥的时间时6分钟,结果又是什么呢?有没有什么规律呢,或者说有没有个公式来计算呢?用编程怎么解?

求教大神?先睡了,尝试下编程解决!


三、编程解决

2016年10月7日01:39:55
本来当时写博客的第二天就用编程解决了这个问题的,可是因为种种原因,还没有时间把代码贴上来!

import java.util.ArrayList;

public class Pilgrimage {

    final static int times[] = { 1, 2, 5, 10 };// 花费时间
    final static String names[] = { "大师兄", "二师兄", "三师兄", "师傅" };// 人物

    public static void main(String[] args) {
        Integer other_bridges[] = { 0, 0, 0, 0 };// 桥另一边
        Integer bridges[] = { 1, 1, 1, 1 };// 当前桥这边 ,1表示存在,0表示不在

        // 开始递归
        loop(bridges, other_bridges, 0, new StringBuffer());
    }

    private static void loop(Integer[] bridges, Integer[] other_bridges,
            int time, StringBuffer msg) {
        ArrayList<Integer> positions = new ArrayList<Integer>();// 记录还在起始端人的下标
        for (int i = 0; i < bridges.length; i++) {
            if (bridges[i] == 1) {
                positions.add(i);// 记录下标
            }
        }
        int len = positions.size();

        for (int i = 0; i < len - 1; i++) {
            for (int j = i + 1; j < len; j++) { // 循环取结合
                // 记录状态
                Integer[] zt_bridges = bridges.clone();
                Integer[] zt_other_bridges = other_bridges.clone();
                int zt_time = time;
                StringBuffer zt_msg = new StringBuffer(msg);

                // 过桥---------
                time += times[positions.get(j)];// 花费时间直接取最大的
                move(bridges, other_bridges, 1, positions.get(i));
                move(bridges, other_bridges, 1, positions.get(j));
                msg.append(" 过桥:" + names[positions.get(i)] + "&"
                        + names[positions.get(j)]);
                // System.out.print(" 过桥:" + names[positions.get(i)] + "_"
                // + names[positions.get(j)]);

                // 回来接人------
                if (isend(other_bridges)) {
                    msg.append(" 总共花费:" + time);
                    System.out.println(msg.toString());
                    // System.out.println(" 总共花费:" + time);
                    return;
                }
                int k = 0;
                for (int ii = 0; ii < other_bridges.length; ii++) {// 选择最快的回来
                    if (other_bridges[ii] == 1) {
                        k = ii;
                        break;
                    }
                }
                time += times[k];
                move(bridges, other_bridges, 0, k);
                msg.append("  回来:" + names[k]+"  ***  ");
                // System.out.print(" 回来:" + names[k]);

                // 继续循环遍历
                loop(bridges.clone(), other_bridges.clone(), time,
                        new StringBuffer(msg));

                // 还原状态
                bridges = zt_bridges;
                other_bridges = zt_other_bridges;
                time = zt_time;
                msg = zt_msg;
            }
        }
    }

    /**
     * 移动的那个人
     * 
     * @param bridges
     * @param other_bridges
     * @param direction
     *            方向
     * @param position
     */
    private static void move(Integer[] bridges, Integer[] other_bridges,
            int direction, int position) {
        if (direction == 1) {// 往另一端走
            bridges[position] = 0;
            other_bridges[position] = 1;
        } else {// 回来接人走
            bridges[position] = 1;
            other_bridges[position] = 0;
        }
    }

    // 判断是否已经结束了
    // 当other_bridges {1,1,1,1}表示结束
    private static boolean isend(Integer[] other_bridges) {
        for (int i : other_bridges) {
            if (i == 0)
                return false;
        }
        return true;
    }

}

运行的结果:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值