師徒四人西天取經,途中必需跨過一座橋,四我的從橋的同一端出發,你得幫助他們到達另外一端,天色很暗而他們只有一支手電筒,一次同時最多能夠有兩我的一塊兒通過橋。而過橋的時候必須持有手電筒,因此就得有人把手電筒帶來帶去,來回橋兩端。手電筒不能用丟的方式來傳遞,四我的的步行速度各不一樣,若兩人同行則以較慢者的速度爲準,大師兄需花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