|
爱因斯坦的难题
传说下面是爱因斯坦在20世纪初出的一道测试题。他说世界上有99%的人回答不出这道题, 看看你是否属于另外的1%?题目如下:
前提: 1 有五栋五种颜色的房子 2 每一位房子的主人国籍都不同 3 这五个人每人只喝一种饮料,只抽一种牌子的香烟,只养一种宠物 4 没有人有相同的宠物,抽相同牌子的香烟,喝相同的饮料 条件: 1 英国人住在红房子里 2 瑞典人养了一条狗 3 丹麦人喝茶 4 绿房子在白房子左边 5 绿房子主人喝咖啡 6 抽PALL MALL烟的人养了一只鸟 7 黄房子主人抽DUNHILL烟 8 住在中间那间房子的人喝牛奶 9 挪威人住第一间房子 10 抽BLENDS烟的人住在养猫人的旁边 11 养马人住在DUNHILL烟的人旁边 12 抽BLUE MASTER烟的人喝啤酒 13 德国人抽PRINCE烟 14 挪威人住在蓝房子旁边 15 抽BLENDS烟的人的邻居喝矿泉水 问题:谁养鱼?
解法: 利用数组和循环: 用5个数组(数组名)表示5种属性,用1、2、3、4、5分别代替各种属性的具体取值 数组的下标表示房间号,数组元素的取值表示某房间某属性的具体取值的代号 房间号(即数组下标)也表示方位,房间号小的为左,大的为右,下标相邻即房间相邻
房间 0 1 2 3 4
国家 挪 德 瑞 英 丹 ---> a[5] 颜色 绿 蓝 黄 红 白 ---> b[5] 饮品 咖 水 奶 酒 茶 ---> c[5] 香烟 blends prince dunhill blue pall ---> d[5] 宠物 鱼 猫 狗 马 鸟 ---> e[5]
取值 1 2 3 4 5 ---> 数组元素的取值
条件化简: 1 英---红 若a[i]=4,则b[i]=4 2 瑞---狗 若a[i]=3,则e[i]=3 3 丹---茶 若a[i]=5,则c[i]=5 4 绿---在白左面 若b[i]=1,b[j]=5,则i<j 5 绿---咖 若b[i]=1,则c[i]=1 6 鸟---pall 若e[i]=5,则d[i]=5 7 黄---dunhill 若b[i]=3,则d[i]=3 8 中间房子---奶 c[2]=3 9 挪---第1间房 a[0]=1 10 猫---有blends邻居 若e[i]=2,则d[i-1]=1 ¦¦ d[i+1]=1 11 马---有dunhill邻居 若e[i]=4,则d[i-1]=3 ¦¦ d[i+1]=3 12 酒---blue 若c[i]=4,则d[i]=4 13 德---prince 若a[i]=2,则d[i]=2 14 挪---有蓝邻居 ==〉b[1]=2 15 水---有blends邻居 若c[i]=2,则d[i-1]=1 ¦¦ d[i+1]=1
C++源代码:
//爱因斯坦难题 //程序设计:万道濮 //说明:此版本是完美版 #include<iostream.h>
int main() { cout<<endl; cout<<" * 爱因斯坦难题 * \n"; cout<<" 程序设计开发:万道濮\n"; cout<<" [2005.1.15]\n"; cout<<"================================================================================"; int a[5],b[5],c[5],d[5],e[5],t[120][5]; //定义所需数组 int i,j,c1,c2,c3,c4,p1,p2,p3,p4,p5; //定义所需变量 char cmd; //cmd用来暂存用户输入的命令 int k; //k用来计数
cout<<" 传说下面是爱因斯坦在20世纪初出的一道测试题。他说世界上有99%的人回答不出这道题,看看你是否属于另外的1%?题目如下:\n"; cout<<"\n前提:\n"; cout<<" 1 有五栋五种颜色的房子\n"; cout<<" 2 每一位房子的主人国籍都不同\n"; cout<<" 3 这五个人每人只喝一种饮料,只抽一种牌子的香烟,只养一种宠物 \n"; cout<<" 4 没有人有相同的宠物,抽相同牌子的香烟,喝相同的饮料 \n"; cout<<"条件:\n"; cout<<" 1 英国人住在红房子里 \n";
cout<<" 2 瑞典人养了一条狗 \n"; cout<<" 3 丹麦人喝茶\n"; cout<<" 4 绿房子在白房子左边 \n"; cout<<" 5 绿房子主人喝咖啡 \n"; cout<<" 6 抽PALL MALL烟的人养了一只鸟 \n"; cout<<" 7 黄房子主人抽DUNHILL烟\n"; cout<<" 8 住在中间那间房子的人喝牛奶 \n"; cout<<" 9 挪威人住第一间房子 \n"; cout<<" 10 抽BLENDS烟的人住在养猫人的旁边\n"; cout<<" 11 养马人住在DUNHILL烟的人旁边 \n"; cout<<" 12 抽BLUE MASTER烟的人喝啤酒\n"; cout<<" 13 德国人抽PRINCE烟 \n"; cout<<" 14 挪威人住在蓝房子旁边 \n"; cout<<" 15 抽BLENDS烟的人的邻居喝矿泉水\n"; cout<<"问题:谁养鱼?\n"; cout<<"\n"; sl: cout<<"输入“k”开始解答此难题,输入“q”退出程序:"; cin>>cmd; cout<<endl; if(cmd=='q' ¦¦ cmd=='Q') return 0; //退出程序 else if(cmd=='k' ¦¦ cmd=='K') goto key; //开始解答难题 else goto sl;
//先求1、2、3、4、5五个数字的所有排列情况 //下面开始用排列组合的方法排列5个数字 key:k=0; //k记录排列组合的种数 p1=0; //初始化下面循环所需参数为0 while(5-p1) //先放置数字1,数字1有5个位置可以选择 { for(i=0;i<5;i++) //每次从下层循环回到此处都要先清空上次的排列 a[i]=0; p1++; //p1记录数字1的当前放置次数 for(i=0,c1=0;i<5;i++) if(a[i]==0) {c1++; if(c1==p1) {a[i]=1; i=5;}} //放置数字1
p2=0; //初始化下面循环所需参数为0 while(4-p2) //放置数字2,放置好数字1后,数字2有4个位置可以选择 { for(i=0;i<5;i++) //每次从下层循环回到此处都要先清除上次排列中的2、3、4、5 if(a[i]!=1) a[i]=0; p2++; //p2记录数字2的当前放置次数 for(i=0,c2=0;i<5;i++) if(a[i]==0) {c2++; if(c2==p2) {a[i]=2; i=5;}}
p3=0; //初始化下面循环所需参数为0 while(3-p3) //放置数字3,放置好数字2后,数字3有3个位置可以选择 { for(i=0;i<5;i++) //每次从下层循环回到此处都要先清除上次排列中的3、4、5 if(a[i]==3 ¦¦ a[i]==4 ¦¦ a[i]==5) a[i]=0; p3++; //p3记录数字3的当前放置次数 for(i=0,c3=0;i<5;i++) if(a[i]==0) {c3++; if(c3==p3) {a[i]=3;i=5;}}
p4=0; //初始化下面循环所需参数为0 while(2-p4) //放置数字4,放置好数字3后,数字4有2个位置可以选择 { for(i=0;i<5;i++) //每次从下层循环回到此处都要先清除上次排列中的4、5 if(a[i]==4 ¦¦ a[i]==5) a[i]=0; p4++; //p4记录数字4的当前放置次数 for(i=0,c4=0;i<5;i++) if(a[i]==0) {c4++; if(c4==p4) {a[i]=4;i=5;}}
for(i=0;i<5;i++) //放置数字5,放置好数字4后,只剩1个位置来放5,故不用循环 if(a[i]==0) {a[i]=5;i=5;} //k记录排列组合的种数
//五个数字的一种排列完成,将此排列记录在数组t[k][5]中 for(i=0;i<5;i++) {t[k][i]=a[i];} k++; //k记录排列组合的种数 } } } } //1、2、3、4、5五个数字的所有排列情况算完,都记录在数组t[][]中 //下面开始用t[][]中的排列组合所有属性,并判断这种组合是否满足题意 k=0; //k记录正确答案的个数 p1=0; while(120-p1) //通过循环组合“国家”属性 { //9 挪---第1间房 ==>a[0]=1 if(t[p1][0]!=1) {p1++; continue;} //9 挪---第1间房 a[0]=1 for(i=0;i<5;i++) {a[i]=t[p1][i];} //a[]放置上第p1种国家属性的排列 p1++; //p1指向下一种排列情况
p2=0; while(120-p2) //通过循环组合“颜色”属性 { //14 挪---有蓝邻居 ==>b[1]=2 if(t[p2][1]!=2) {p2++; continue;} //14 挪---有蓝邻居 ==〉b[1]=2 for(i=0;i<5;i++) {b[i]=t[p2][i];} // p2++; //p1指向下一种排列情况
p3=0; while(120-p3) //通过循环组合“饮品”属性 { //8 中间房子---奶 ==>c[2]=3 if(t[p3][2]!=3) {p3++; continue;} //8 中间房子---奶 c[2]=3 for(i=0;i<5;i++) {c[i]=t[p3][i];} // p3++; //p1指向下一种排列情况
p4=0; while(120-p4) //通过循环组合“香烟”属性 { for(i=0;i<5;i++) {d[i]=t[p4][i];} p4++;
p5=0; while(120-p5) //通过循环组合“宠物”属性 { for(i=0;i<5;i++) {e[i]=t[p5][i];} p5++;
/*测试 cout<<" 房间 国家 颜色 饮品 香烟 宠物\n\n"; for(i=0;i<5;i++) { cout<<" "<<i+1<<" "<<a[i]<<" "<<b[i]<<" "<<c[i]<<" "<<d[i]<<" "<<e[i]<<endl; } //return 0; //测试完毕*/
//所有属性的一种组和完成,下面判断这种组合是否满足题意 //若有一个条件不满足,就退出本次循环,并继续下次循环,即下一组组合
//1 英---红 若a[i]=4,则b[i]=4 for(i=0;i<5;i++) {if(a[i]==4) break;} if(b[i]!=4) continue; //退出本次循环,并继续下次循环,即下一组组合
//2 瑞---狗 若a[i]=3,则e[i]=3 for(i=0;i<5;i++) {if(a[i]==3) break;} if(e[i]!=3) continue; //退出本次循环,并继续下次循环,即下一组组合
//3 丹---茶 若a[i]=5,则c[i]=5 for(i=0;i<5;i++) {if(a[i]==5) break;} if(c[i]!=5) continue; //退出本次循环,并继续下次循环,即下一组组合
//4 绿---在白左面 若b[i]=1,b[j]=5,则i<j for(i=0;i<5;i++) {if(b[i]==1) break;} for(j=0;j<5;j++) {if(a[j]==5) break;} if(i>=j) continue; //退出本次循环,并继续下次循环,即下一组组合
//5 绿---咖 若b[i]=1,则c[i]=1 for(i=0;i<5;i++) {if(b[i]==1) break;} if(c[i]!=1) continue;
//6 鸟---pall 若e[i]=5,则d[i]=5 for(i=0;i<5;i++) {if(e[i]==5) break;} if(d[i]!=5) continue;
//7 黄---dunhill 若b[i]=3,则d[i]=3 for(i=0;i<5;i++) {if(b[i]==3) break;} if(d[i]!=3) continue;
//10 猫---有blends邻居 若e[i]=2,则d[i-1]=1 ¦¦ d[i+1]=1 for(i=0;i<5;i++) {if(e[i]==2) break;} if(i==0) {if(d[i+1]!=1) continue;} if(i>0 && i<4) {if(d[i-1]!=1 && d[i+1]!=1) continue;} if(i==4) {if(d[i-1]!=1) continue;}
//11 马---有dunhill邻居 若e[i]=4,则d[i-1]=3 ¦¦ d[i+1]=3 for(i=0;i<5;i++) {if(e[i]==4) break;} if(i==0) {if(d[i+1]!=3) continue;} if(i>0 && i<4) {if(d[i-1]!=3 && d[i+1]!=3) continue;} if(i==4) {if(d[i-1]!=3) continue;}
//12 酒---blue 若c[i]=4,则d[i]=4 for(i=0;i<5;i++) {if(c[i]==4) break;} if(d[i]!=4) continue;
//13 德---prince 若a[i]=2,则d[i]=2 for(i=0;i<5;i++) {if(a[i]==2) break;} if(d[i]!=2) continue;
//15 水---有blends邻居 若c[i]=2,则d[i-1]=1 ¦¦ d[i+1]=1 for(i=0;i<5;i++) {if(c[i]==2) break;} if(i==0) {if(d[i+1]!=1) continue;} if(i>0 && i<4) {if(d[i-1]!=1 && d[i+1]!=1) continue;} if(i==4) {if(d[i-1]!=1) continue;}
//所有条件都判断完毕,若程序执行到此而没有退出本次循环 //说明此组合满足题意,是正确答案,下面就输出这种组合 //输出答案后,继续判断下一种组合,看是否还有其他答案 k++; //k记录正确答案的个数 cout<<"\n————————爱因斯坦难题答案————————\n\n"; //下面输出所问问题的答案 cout<<" 第"<<k<<"种答案: "; for(i=0;i<5;i++) //寻找养鱼的人对应的数组元素 {if(e[i]==1) break;} switch (a[i]) { case 1: cout<<"挪威人养鱼\n\n"; break; case 2: cout<<"德国人养鱼\n\n"; break; case 3: cout<<"瑞士人养鱼\n\n"; break; case 4: cout<<"英国人养鱼\n\n"; break; case 5: cout<<"丹麦人养鱼\n\n"; break; }//问题答案输出完毕 cout<<" 左 <---|---> 右\n\n"; cout<<" 房间 1 2 3 4 5\n\n"; //输出答案的所有“国家”属性 cout<<" 国家 "; for(i=0;i<5;i++) { switch (a[i]) { case 1: cout<<"挪威 "; break; case 2: cout<<"德国 "; break; case 3: cout<<"瑞士 "; break; case 4: cout<<"英国 "; break; case 5: cout<<"丹麦 "; break; } } cout<<"\n\n"; //换行 //输出答案的所有“颜色”属性 cout<<" 颜色 "; for(i=0;i<5;i++) { switch (b[i]) { case 1: cout<<"绿色 "; break; case 2: cout<<"蓝色 "; break; case 3: cout<<"黄色 "; break; case 4: cout<<"红色 "; break; case 5: cout<<"白色 "; break; } } cout<<"\n\n"; //换行 //输出答案的所有“饮品”属性 cout<<" 饮品 "; for(i=0;i<5;i++) { switch (c[i]) { case 1: cout<<"咖啡 "; break; case 2: cout<<"泉水 "; break; case 3: cout<<"牛奶 "; break; case 4: cout<<"啤酒 "; break; case 5: cout<<"绿茶 "; break; } } cout<<"\n\n"; //换行 //输出答案的所有“香烟”属性 cout<<" 香烟 "; for(i=0;i<5;i++) { switch (d[i]) { case 1: cout<<"blends "; break; case 2: cout<<"prince "; break; case 3: cout<<"dunhill "; break; case 4: cout<<"blue "; break; case 5: cout<<"pall "; break; } } cout<<"\n\n"; //换行 //输出答案的所有“宠物”属性 cout<<" 宠物 "; for(i=0;i<5;i++) { switch (e[i]) { case 1: cout<<"鱼 "; break; case 2: cout<<"猫 "; break; case 3: cout<<"狗 "; break; case 4: cout<<"马 "; break; case 5: cout<<"鸟 "; break; } }//答案的所有属性输出完毕 cout<<"\n\n"; //换行 }//通过循环组合“宠物”属性的循环完毕 }//通过循环组合“香烟”属性的循环完毕 }//通过循环组合“饮品”属性的循环完毕 }//通过循环组合“颜色”属性的循环完毕 }//通过循环组合“国家”属性的循环完毕 cout<<endl; cout<<"====================计算完毕===================\n\n"; cout<<" 一共有以上 "<<k<<"种正确答案\n\n"; cout<<"================程序设计:万道濮===============\n\n"; s2: cout<<"输入“r”重新解答此难题,输入“q”退出程序:"; cin>>cmd; cout<<endl; if(cmd=='q' ¦¦ cmd=='Q') return 0; //正常退出程序 else if(cmd=='r' ¦¦ cmd=='R') goto key; //重新解答难题 else goto s2; }//主程序main()结束
最后答案: 正确答案一共有六个。
|