师徒四人西天取经,途中必需跨过一座桥,四我的从桥的同一端出发,你得帮助他们到达另外一端,天色很暗而他们只有一支手电筒,一次同时最多能够有两我的一块儿通过桥。而过桥的时候必须持有手电筒,因此就得有人把手电筒带来带去,来回桥两端。手电筒不能用丢的方式来传递,四我的的步行速度各不一样,若两人同行则以较慢者的速度为准,大师兄需花1分钟过桥,二师兄需花2分钟过桥,三师兄需花5分钟过桥,师傅需花10分钟过桥。请问他们最短在多少分钟内过桥?()
A. 18
B. 17
C. 19
D. 16java
一开始直接想到,用最小的那个数来回跑,也就是大师兄来回跑,算出来是19,但是又想了下,以下:
一、大师兄和二师兄过桥,算二师兄的时间也就是2分钟
二、大师兄独自拿手电回来 1分钟
三、三师弟和师傅那手电过桥,算师傅的时间也就是10分钟
四、二师弟拿手电回来 2分钟
五、最后大师兄和二师弟过桥 2分钟
总共17分钟编程
虽然结果出来了,感受有点不实在,这其中的规律是怎样的呢?有没有什么规律解决这相似的问题呢,好比只有三我的过桥呢?二师兄不过桥,结果又是什么呢?再好比,多一我的过桥呢?多了个白龙马过桥,白龙马过桥的时间时6分钟,结果又是什么呢?有没有什么规律呢,或者说有没有个公式来计算呢?用编程怎么解?app
求教大神?先睡了,尝试下编程解决!oop
2016年10月7日01:39:55
原本当时写博客的次日就用编程解决了这个问题的,但是由于种种缘由,尚未时间把代码贴上来!spa
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; } }
运行的结果:
code