爱因斯坦思考题(多维穷举)
来源:互联网 发布:文艺知乎 编辑:程序博客网 时间:2024/05/21 07:47
爱因斯坦有一道思考题,据说世界上只有2%的人可以解答。
题目是这样的,据说有五个不同颜色的房间排成一排,每个房间里分别住着一个不同国籍的人,每个人都喝一种特定品牌的饮料,抽一种特定品牌的烟,养一种宠物,没有任意两个人抽相同品牌的香烟,或喝相同品牌的饮料,或养相同的宠物,问题是谁在养鱼作为宠物?为了寻找答案,爱因斯坦给出了十五条线索:
(1)、英国人住在红色的房子里;
(2)、瑞典人养狗作为宠物;
(3)、丹麦人喝茶;
(4)、绿房子紧挨着白房子,在白房子的左边;
(5)、绿房子的主人喝咖啡;
(6)、抽Pall Mall牌香烟的人养鸟;
(7)、黄色房子里的人抽Dunhill牌香烟;
(8)、住在中间那个房子里的人喝牛奶;
(9)、挪威人住在第一个房子里面;
(10)、抽Blends牌香烟的人和养猫的人相邻;
(11)、养马的人和抽Dunhill牌香烟的人相邻;
(12)、抽BlueMaster牌香烟的人和啤酒;
(13)、德国人抽Prince牌香烟;
(14)、挪威人和住在蓝房子的人相邻;
(15)、抽Blends牌香烟的人和喝矿泉水的人相邻。
这道题是一道逻辑推理题,按照我们常人的思维就是拿出一张纸和一支笔,然后用假设法慢慢去推倒,但是也肯定要想很久。
于是我们想到了把推理的过程交给计算机去做,但是怎么做呢?计算机不会思考?
计算机不会思考,但是会计算,我们可以让计算机算出最终答案。
解题思路:1.穷举所有的组合结果 2.对结果进行判断
多维穷举算法:
整个算法的过程就是这两个核心的整合。
先建立数学模型:把问题抽象成一个二维数组,data[i][j],其中下标i代表大类(房子颜色、宠物等),j代表的是小类(绿色、蓝色、猫和狗等)。
然后通过多个递归排列组合算法进行穷举。
结果判断:
结果判断分成三大类,一类是组内关系绑定,第二类是组间关系绑定,第三类是过滤线索。
组内关系绑定是一个属性类型和一个值绑定,如:绿房子的主人喝咖啡,丹麦人喝茶。
组间关系绑定是一个组和相邻的组之间产生关系,如:挪威人住在蓝房子的人相邻,抽Blends牌香烟的人和喝矿泉水的人相邻。
过滤类线索是很难归为一二类绑定关系的判断条件,我们只能通过在穷举算法中过滤掉。
这个爱因斯坦思考题也是《算法的乐趣》上的,但是作者没有给代码,所以我只能够自己写,本来以为判断是难点,后来发现排列组合也是难点之一,就在百度上搜了一下排列组合的算法,然后自己先用算法穷举所有可能的组合,然后再用java里面的枚举类去处理组间组内的判断关系,整个过程没有任何的代码参考,完完全全是思考的结果,不像倒水问题和妖怪和尚过河有作者的C++代码。
所以这对我来说也是一个巨大的挑战,但是我最终战胜了困难,解出了这道题。
下面一张图是代码运行出现结果的图,我对照了书上的最终结果,完全正确:
将近两亿个枚举,我的算法不够好,用了接近15秒的时间才解出这道题。
下面是我的实现代码:
Test类是主类,用于启动程序
package 二维穷举爱因斯坦的思考题_待完成;public class Test { public static int[] text = {0,1,2,3,4}; public static int count; public static int judge1; public static int judge2; public static void main(String[] args) { Test ts = new Test(); ts.initMain(); } public void initMain(){ long time1 = System.currentTimeMillis(); Think tk = new Think(); tk.initThink(tk.data, 0, text.length); long time2 = System.currentTimeMillis(); System.out.println("花费的时间:"+(time2 - time1)); System.out.println("多维穷举次数是:"+count); }}
Think类是多维穷举算法实现类,用于穷举排列组合:
package 二维穷举爱因斯坦的思考题_待完成;public class Think{/** * 一维的分别是:房子颜色、国籍、饮料、香烟、宠物 * 二维排列随机排列组合检测 * red green white yellow blue * 1.红 2.绿 3. 白 4.黄 5.蓝 * britain swedend norway germany denmark * 1.英国2. 瑞典 3.挪威 4.德国 5.丹麦 * tea coffee milk beer water * 1.茶 2. 咖啡 3.牛奶 4.啤酒 5.水 * dog cat fish bird horse * 1.狗 2. 猫 3.鱼 4.鸟 5.马 * pallmall bunhill blends bluemaster prince * 1 2 3 4 5 */public int[][] data = new int[5][5];//定义一个二维数组存放分组数据public static int[] norway = {2,1,4,5};public int j;public Think(){{for(int i=0;i<data.length;i++){for(int j=0;j<data[i].length;j++){data[i][j] = j+1;}}}}public static void initThink(int[] data[],int m,int n){//遍历1次int j = 0;if(m < n - 1){initThink(data, m + 1, n);for (int i = m + 1; i < n; i++) { int t = data[j][m]; data[j][m] = data[j][i]; data[j][i] = t; initThink(data, m + 1, n); t = data[j][m]; data[j][m] = data[j][i]; data[j][i] = t;// if( !(data[j][m] == 2 && data[j][m+1] == 3) ){//如果绿房子右边不是白房子就返回//return ;//} }}else {for(int i=0;i<5;i++){try{if( data[j][i] == 2 && data[j][i+1] == 3 ){secondThink(norway, 0, norway.length,data);}}catch(Exception e){}}}}public static void secondThink(int[] norway,int m,int n,int[] data[]){//遍历第二次if(m < n - 1){secondThink(norway, m + 1, n,data);for (int i = m + 1; i < n; i++) { int t = norway[m]; norway[m] = norway[i]; norway[i] = t; secondThink(norway, m + 1, n,data); t = norway[m]; norway[m] = norway[i]; norway[i] = t; }}else{for(int k=0;k<5;k++){if( k == 0 ){data[1][k] = 3;}else{data[1][k] = norway[k-1];}}ThreeThink(data, 0, data.length);}}public static void ThreeThink(int[] data[],int m,int n){//遍历第三次int j = 2;if(m < n - 1){ThreeThink(data, m + 1, n);for (int i = m + 1; i < n; i++) { int t = data[j][m]; data[j][m] = data[j][i]; data[j][i] = t; ThreeThink(data, m + 1, n); t = data[j][m]; data[j][m] = data[j][i]; data[j][i] = t; }}else{if( data[j][2] != 3 ){//中间房子的主人喝牛奶,如果中间房主不喝牛奶就返回return ; }FourThink(data, 0, data.length);}}public static void FourThink(int[] data[],int m,int n){//遍历第四次int j = 3;if(m < n - 1){FourThink(data, m + 1, n);for (int i = m + 1; i < n; i++) { int t = data[j][m]; data[j][m] = data[j][i]; data[j][i] = t; FourThink(data, m + 1, n); t = data[j][m]; data[j][m] = data[j][i]; data[j][i] = t; }}else{FiveThink(data, 0, data.length);}}public static void FiveThink(int[] data[],int m,int n){//遍历第五次int j = 4;if(m < n - 1){FiveThink(data, m + 1, n);for (int i = m + 1; i < n; i++) { int t = data[j][m]; data[j][m] = data[j][i]; data[j][i] = t; FiveThink(data, m + 1, n); t = data[j][m]; data[j][m] = data[j][i]; data[j][i] = t; }}else{Test.count++;if( Tool.judge1(data) && Tool.judge2(data) ){System.out.println("算法推理成功!结果是:");Tool.print(data);System.out.println();Tool.printCorrect();}}}public static void printResult(int[] data) { for (int i = 0; i < data.length; i++) { System.out.print(data[i]+" "); } System.out.println(); }public static void print(int[][] data){for(int i=0;i<data.length;i++){for(int j=0;j<data[0].length;j++){System.out.print(data[i][j] +" ");}System.out.println();}}}
Tool类是判断实现类,实现组间组内绑定关系的条件判断:
package 二维穷举爱因斯坦的思考题_待完成;public class Tool {public static int[][] ans = {{4,5,1,2,3},{3,5,1,4,2},{5,1,3,2,4},{2,5,4,3,1},{2,3,1,5,4}};public static int count;public static boolean judge1(int[] data[]){for(int i=0;i<InGroupRelation.values().length;i++){int ft = InGroupRelation.values()[i].firstType;int st = InGroupRelation.values()[i].secondType;int fv = InGroupRelation.values()[i].firstvalue;int sv = InGroupRelation.values()[i].secondvalue;for(int j=0;j<5;j++){if( data[ft][j] == fv && data[st][j] == sv ){//判断排列组合,成立就跳出,不成立就返回falsebreak;}if(j == 4){return false;}}}return true;}public static boolean judge2(int[] data[]){for(int i=0;i<OutOfFroupRelation.values().length;i++){int ft = OutOfFroupRelation.values()[i].firstType;int st = OutOfFroupRelation.values()[i].secondType;int fv = OutOfFroupRelation.values()[i].firstValue;int sv = OutOfFroupRelation.values()[i].secondValue;for(int j=0;j<5;j++){try{if( data[ft][j] == fv && (data[st][j+1] == sv || data[st][j-1] == sv) ){break;}}catch(Exception e){}if(j == 4){return false;}}}return true;}public static void print(int[] data[]){for(int i=0;i<data.length;i++){for(int j=0;j<data[i].length;j++){System.out.print(data[i][j]+" ");}System.out.println();}}public static boolean check(int[] data[]){for(int i=0;i<data.length;i++){for(int j=0;j<data[i].length;j++){if(data[i][j] != ans[i][j]){return false;}}}count++;return true;}public static void printCorrect(){System.out.println("4:黄色5:蓝色1:红色2:绿色3:白色");System.out.println("3:挪威5:丹麦1:英国4:德国2:瑞典");System.out.println("5:水 1:茶3:牛奶2:咖啡4:啤酒");System.out.println("2:猫5:马4:鸟3:鱼1:狗 ");System.out.println("2:Bunhill3:Blends1:PallMall5:Prince4:BlueMaster");}}
InGroupRelation类给定组内关系:
package 二维穷举爱因斯坦的思考题_待完成;public enum InGroupRelation {red_england(0,1,1,1),swedend_dog(1,3,2,1),danmark_tea(1,2,5,1),green_coffee(0,2,2,2),pallmall_bird(4,3,1,4),yellow_dunhill(0,4,4,2),bluemaster_beer(4,2,4,4),germany_prince(1,4,4,5);public int[][] data = new int[5][5];public int firstType,secondType,firstvalue,secondvalue;InGroupRelation(int firstType,int secondType,int firstvalue,int secondvalue){this.firstType = firstType;this.secondType = secondType;this.firstvalue = firstvalue;this.secondvalue = secondvalue;}}
OutOfFroupRelation类给定组间关系:
package 二维穷举爱因斯坦的思考题_待完成;public enum OutOfFroupRelation {blends_cat(4,3,3,2),horse_dunhill(3,4,5,2),norway_blue(1,0,3,5),blends_drink_water(4,2,3,5);public int firstType,secondType,firstValue,secondValue;OutOfFroupRelation(int firstType,int secondType,int firstValue,int secondValue){this.firstType = firstType;this.secondType = secondType;this.firstValue = firstValue;this.secondValue = secondValue;}}这就是我这几天做的多维穷举算法。
我觉得学习算法一定要思路清晰,头昏脑涨的时候最好不要学习算法,因为那时候效率很低,往往学不到东西,还浪费时间。
作者博客:
http://blog.csdn.net/orbit/article/details/6994575
- 爱因斯坦思考题(多维穷举)
- 爱因斯坦的思考题
- 爱因斯坦的思考题
- 爱因斯坦的思考题
- 有趣的爱因斯坦的思考题
- 爱因斯坦的思考题(手推)
- 算法系列之七:爱因斯坦的思考题(上)
- 算法系列之七:爱因斯坦的思考题(上)
- 算法系列之七:爱因斯坦的思考题(上)
- 算法系列之七:爱因斯坦的思考题(下)
- 算法系列之七:爱因斯坦的思考题(上)
- 算法系列之七:爱因斯坦的思考题(下)
- 算法系列之七:爱因斯坦的思考题(下)
- 算法系列之七:爱因斯坦的思考题(上)
- 算法系列之七:爱因斯坦的思考题(上)
- 算法系列之七:爱因斯坦的思考题(下)
- 算法系列之七:爱因斯坦的思考题(上) .
- 算法系列之七:爱因斯坦的思考题(下) .
- RxJava之Schedulers详解
- 升级10.11后Xcode的CocoaPods插件报错
- wifidog接口文档
- 第三章:WORKING WITH TEXT DATA
- mysql-删除重复的数据,重复的数据只保留一条
- 爱因斯坦思考题(多维穷举)
- 学习理论-贝叶斯统计和正则化
- 转载_架构师重构代码的12条军规
- 简单打开.swf文件
- 如何判断服务器返回的图片类型为GIF
- C++作业3
- 基础 HTML之目录问题(相对路径和绝对路径区别)
- HTML JS HTTP 精品插件记录
- 100个常用的 PHP 类库、资源和技巧小结