一、题目概述
师徒四人西天取经,途中必需跨过一座桥,四个人从桥的同一端出发,你得帮助他们到达另一端,天色很暗而他们只有一支手电筒,一次同时最多可以有两个人一起经过桥。而过桥的时候必须持有手电筒,所以就得有人把手电筒带来带去,来回桥两端。手电筒不能用丢的方式来传递,四个人的步行速度各不同,若两人同行则以较慢者的速度为准,大师兄需花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;
}
}
运行的结果: