題目
有4 張紅色的牌和4 張藍色的牌,主持人先拿任意兩張,再分別在A、B、C 三人額頭上貼任意兩張牌,A、B、C 三人都可以看見其餘兩人額頭上的牌,看完後讓他們猜自己額頭上是什麼顏色的牌,A 說不知道,B 說不知道,C 說不知道,然後A 說知道了。請教如何推理,A 是怎麼知道的。如果用程式,又怎麼實現呢。
解題思路
首先組合的情形是3×3×3 = 27
public void group() { String[] arg = { "藍-藍", "紅-紅", "紅-藍" }; int size = arg.length; int index = 0; for (int i = 0; i < size; i++) { String A = arg[i]; for (int j = 0; j < size; j++) { String B = arg[j]; for (int k = 0; k < size; k++) { String C = arg[k]; index++; String group = String.format("%s-%s-%s", A, B, C); String groupStr = String.format("%s %s %s", A, B, C); System.out.print(index + ": "); System.out.println(groupStr); } } } }
1: 藍-藍 藍-藍 藍-藍2: 藍-藍 藍-藍 紅-紅3: 藍-藍 藍-藍 紅-藍4: 藍-藍 紅-紅 藍-藍5: 藍-藍 紅-紅 紅-紅6: 藍-藍 紅-紅 紅-藍7: 藍-藍 紅-藍 藍-藍8: 藍-藍 紅-藍 紅-紅9: 藍-藍 紅-藍 紅-藍10: 紅-紅 藍-藍 藍-藍11: 紅-紅 藍-藍 紅-紅12: 紅-紅 藍-藍 紅-藍13: 紅-紅 紅-紅 藍-藍14: 紅-紅 紅-紅 紅-紅15: 紅-紅 紅-紅 紅-藍16: 紅-紅 紅-藍 藍-藍17: 紅-紅 紅-藍 紅-紅18: 紅-紅 紅-藍 紅-藍19: 紅-藍 藍-藍 藍-藍20: 紅-藍 藍-藍 紅-紅21: 紅-藍 藍-藍 紅-藍22: 紅-藍 紅-紅 藍-藍23: 紅-藍 紅-紅 紅-紅24: 紅-藍 紅-紅 紅-藍25: 紅-藍 紅-藍 藍-藍26: 紅-藍 紅-藍 紅-紅27: 紅-藍 紅-藍 紅-藍
然後再通過一些條件過濾掉上面組合中一些選項
條件1.組合中的紅的數量或者藍的數量不能超過4
public void group() {String[] arg = { "藍-藍", "紅-紅", "紅-藍" };int size = arg.length;int index = 0;for (int i = 0; i < size; i++) {String A = arg[i];for (int j = 0; j < size; j++) {String B = arg[j];for (int k = 0; k < size; k++) {String C = arg[k];index++;String group = String.format("%s-%s-%s", A, B, C);String groupStr = String.format("%s %s %s", A, B, C);if (getStrCount(group)) {System.out.print(index + ": ");System.out.println(groupStr);}}}}}public boolean getStrCount(String str) {String[] args = str.split("-");int blueCount = 0;int redCount = 0;for (int i = 0; i < args.length; i++) {if (args[i].equals("藍")) {blueCount++;} else if (args[i].equals("紅")) {redCount++;}}if (blueCount > 4 || redCount > 4) {return false;}return true;}
過濾掉上面編號為1,3,7,14,15,17,19,23八種情況。還剩19種。
2: 藍-藍 藍-藍 紅-紅4: 藍-藍 紅-紅 藍-藍5: 藍-藍 紅-紅 紅-紅6: 藍-藍 紅-紅 紅-藍8: 藍-藍 紅-藍 紅-紅9: 藍-藍 紅-藍 紅-藍10: 紅-紅 藍-藍 藍-藍11: 紅-紅 藍-藍 紅-紅12: 紅-紅 藍-藍 紅-藍13: 紅-紅 紅-紅 藍-藍16: 紅-紅 紅-藍 藍-藍18: 紅-紅 紅-藍 紅-藍20: 紅-藍 藍-藍 紅-紅21: 紅-藍 藍-藍 紅-藍22: 紅-藍 紅-紅 藍-藍24: 紅-藍 紅-紅 紅-藍25: 紅-藍 紅-藍 藍-藍26: 紅-藍 紅-藍 紅-紅27: 紅-藍 紅-藍 紅-藍
條件2.A不知道,B不知道,C不知道。說明三個人當中不能每個人手裡的兩張牌都是一樣的顏色。
反證法:如果出現三個人當中每個人手裡的牌都是顏色一樣的。那麼第一次的時候,3個人當中一眼就直接能猜出來了。
public void group() {String[] arg = { "藍-藍", "紅-紅", "紅-藍" };int size = arg.length;int index = 0;for (int i = 0; i < size; i++) {String A = arg[i];for (int j = 0; j < size; j++) {String B = arg[j];for (int k = 0; k < size; k++) {String C = arg[k];index++;String groupStr = String.format("%s %s %s", A, B, C);// 條件1String group = String.format("%s-%s-%s", A, B, C);if (!getStrCount(group))continue;// 條件2if (!isEveryOneSame(A) && !isEveryOneSame(B)&& !isEveryOneSame(C))continue;System.out.print(index + ": ");System.out.println(groupStr);}}}}// 條件2 private boolean isEveryOneSame(String one) { String[] args = one.split("-"); if (args[0].equals(args[1])) { return true; } return false; }// 條件1private boolean getStrCount(String str) {String[] args = str.split("-");int blueCount = 0;int redCount = 0;for (int i = 0; i < args.length; i++) {if (args[i].equals("藍")) {blueCount++;} else if (args[i].equals("紅")) {redCount++;}}if (blueCount > 4 || redCount > 4) {return false;}return true;}
可能的組合就剩下了下面幾種了。
6: 藍-藍 紅-紅 紅-藍8: 藍-藍 紅-藍 紅-紅9: 藍-藍 紅-藍 紅-藍12: 紅-紅 藍-藍 紅-藍16: 紅-紅 紅-藍 藍-藍18: 紅-紅 紅-藍 紅-藍20: 紅-藍 藍-藍 紅-紅21: 紅-藍 藍-藍 紅-藍22: 紅-藍 紅-紅 藍-藍24: 紅-藍 紅-紅 紅-藍25: 紅-藍 紅-藍 藍-藍26: 紅-藍 紅-藍 紅-紅27: 紅-藍 紅-藍 紅-藍
可以排除編號2,4,5,10,11,13六種情況。還剩13種。
條件3.上面的情況中,要排除C可以根據A,B的不知道,然後可以一眼就能看出自己是什麼牌組合。
這種情況就是A手中的牌顏色是一樣的,B手中的牌顏色也是一樣的。例如6和12
public void group() {String[] arg = { "藍-藍", "紅-紅", "紅-藍" };int size = arg.length;int index = 0;for (int i = 0; i < size; i++) {String A = arg[i];for (int j = 0; j < size; j++) {String B = arg[j];for (int k = 0; k < size; k++) {String C = arg[k];index++;String groupStr = String.format("%s %s %s", A, B, C);// 條件1String group = String.format("%s-%s-%s", A, B, C);if (!getStrCount(group))continue;// 條件2if (isEveryOneSame(A) && isEveryOneSame(B)&& isEveryOneSame(C))continue;// 條件3if (isEveryOneSame(A) && isEveryOneSame(B))continue;System.out.print(index + ": ");System.out.println(groupStr);}}}}// 條件2private boolean isEveryOneSame(String one) {String[] args = one.split("-");if (args[0].equals(args[1])) {return true;}return false;}// 條件1private boolean getStrCount(String str) {String[] args = str.split("-");int blueCount = 0;int redCount = 0;for (int i = 0; i < args.length; i++) {if (args[i].equals("藍")) {blueCount++;} else if (args[i].equals("紅")) {redCount++;}}if (blueCount > 4 || redCount > 4) {return false;}return true;}public static void main(String[] args) {// TODO Auto-generated method stubProblem22 problem = new Problem22();problem.group();}}
還剩下11種情況。
8: 藍-藍 紅-藍 紅-紅9: 藍-藍 紅-藍 紅-藍16: 紅-紅 紅-藍 藍-藍18: 紅-紅 紅-藍 紅-藍20: 紅-藍 藍-藍 紅-紅21: 紅-藍 藍-藍 紅-藍22: 紅-藍 紅-紅 藍-藍24: 紅-藍 紅-紅 紅-藍25: 紅-藍 紅-藍 藍-藍26: 紅-藍 紅-藍 紅-紅27: 紅-藍 紅-藍 紅-藍
得出結果
上面剩下的11中情況都是符合實際的拿牌情況,以及根據A,B,C第一輪都無法判斷出自己手中的牌這些條件過濾後的組合。那麼再根據最後一個第二輪A就已經知道自己的牌了。說明從上面組合中找出,以B,C組合為關鍵字的,A只有一種情況的組合。比如情況8中,B,C組合是“紅-藍 紅-紅”,那麼根據這個去找找看,同樣是這個條件的A還有沒有其他情況。很顯然發現了第26號符合。說明這種組合是不符合要求的。而第20號的“藍-藍 紅-紅”只有一種情況,說明符合要求。那用程式怎麼實現,我們可以以B+C為關鍵字組建一個map,value值為這個關鍵字在上面11情況中出現的次數。這樣我們可以得到出現一次的關鍵字,這樣很容易確定是第幾號。
public class Problem22 { //以BC為關鍵字,次數為value的MAP Map<String,Integer> map = new LinkedHashMap<String,Integer>(); //以BC為關鍵字,組合為value的MAP Map<String,String> map1 = new LinkedHashMap<String,String>(); public void group() { String[] arg = { "藍-藍", "紅-紅", "紅-藍" }; int size = arg.length; int index = 0; for (int i = 0; i < size; i++) { String A = arg[i]; for (int j = 0; j < size; j++) { String B = arg[j]; for (int k = 0; k < size; k++) { String C = arg[k]; index++; String groupStr = String.format("%s %s %s", A, B, C); // 條件1 String group = String.format("%s-%s-%s", A, B, C); if (!getStrCount(group)) continue; // 條件2 if (isEveryOneSame(A) && isEveryOneSame(B) && isEveryOneSame(C)) continue; // 條件3 if (isEveryOneSame(A) && isEveryOneSame(B)) continue; if(map.containsKey(B + C)){ int num = map.get(B+C); map.put(B+C,++num); }else{ map.put(B+C,1); } map1.put(B+C,index + ": "+groupStr); System.out.print(index + ": "); System.out.println(groupStr); } } } Set<Map.Entry<String, Integer>> entrys = map.entrySet(); Iterator<Map.Entry<String, Integer>> iter = entrys.iterator(); //找到次數為1的組合 while(iter.hasNext()){ Map.Entry<String, Integer> entry= iter.next(); if(entry.getValue() ==1){ String answer = map1.get(entry.getKey()); System.out.println("從上面的組合中找到的合格答案為 : "+answer); } } } // 條件2 private boolean isEveryOneSame(String one) { String[] args = one.split("-"); if (args[0].equals(args[1])) { return true; } return false; } // 條件1 private boolean getStrCount(String str) { String[] args = str.split("-"); int blueCount = 0; int redCount = 0; for (int i = 0; i < args.length; i++) { if (args[i].equals("藍")) { blueCount++; } else if (args[i].equals("紅")) { redCount++; } } if (blueCount > 4 || redCount > 4) { return false; } return true; } public static void main(String[] args) { // TODO Auto-generated method stub Problem22 problem = new Problem22(); problem.group(); }}
結果為
8: 藍-藍 紅-藍 紅-紅9: 藍-藍 紅-藍 紅-藍16: 紅-紅 紅-藍 藍-藍18: 紅-紅 紅-藍 紅-藍20: 紅-藍 藍-藍 紅-紅21: 紅-藍 藍-藍 紅-藍22: 紅-藍 紅-紅 藍-藍24: 紅-藍 紅-紅 紅-藍25: 紅-藍 紅-藍 藍-藍26: 紅-藍 紅-藍 紅-紅27: 紅-藍 紅-藍 紅-藍從上面的組合中找到的合格答案為 : 20: 紅-藍 藍-藍 紅-紅從上面的組合中找到的合格答案為 : 21: 紅-藍 藍-藍 紅-藍從上面的組合中找到的合格答案為 : 22: 紅-藍 紅-紅 藍-藍從上面的組合中找到的合格答案為 : 24: 紅-藍 紅-紅 紅-藍
有4種情況下,A可以猜出自己的牌。當然需要A能有這麼強的邏輯。
總結
有沒有發現可能的情況中A 手中的牌都是一樣的:紅藍。所以以後你就猜自己是紅藍就行了吧。