0.积分模式
对于积分模式的介绍,请参见前文http://blog.csdn.net/tobec3sdn/article/details/7065690,主要是用于解决爱因斯坦大难题(也被称为Zebra Puzzle)的。
1.排列算法
这里所说的积分模式是用暴力算法解决的(一千二百亿次的循环,本机Windows运行了一个多小时),也就是穷举了所有情况从而找出所要的结果。首先第一步,就是排列,C++实现代码如下。
#include <stdio.h>
#include <algorithm>
int a[4];
void perm(int l, int r)
{
if (l == r) {
for (int i = 0; i <= r; i++)
{
printf("%d ", a[i]);
}
puts("");
return;
}
for (int i = l; i <= r; i++) {
std::swap(a[l], a[i]);
perm(l + 1, r);
std::swap(a[l], a[i]);
}
}
int main()
{
for (int i = 0; i < 4; i++)
a[i] = i + 1;
perm(0, 3);
}
2.具体解决思路
首先,对所给的自然语言的数据进行编号,如下图。
同时,要对所给条件进行编号的转化。
然后在多次A55的循环中判断是否符合条件,里面还有遍历5次的循环来找到相应的国籍或者宠物。
最后利用积分找到真正的答案。
3.爱因斯坦大难题(Zebra Puzzle)最终答案
挪威人喝水,日本人养斑马。
4.实现代码
/*
* author : tobe
* date : 2012.6.12
* problem : Zebra Puzzle
*
*/
#include<iostream>
#include <algorithm>
using namespace std;
int a[5]; //用原有的排列函数所需要的数组
int indexOfPossibility = 0; //表示第几种可能组合
int nation[120][5]; //表示nation的A55全排列(共120种),二维数组下表才表示每种情况下的国家组合
int color[120][5];
int animal[120][5];
int drink[120][5];
int cigarette[120][5];
void perm(int l, int r)
{
if (l == r) {
for (int i = 0; i <= r; i++)
{
//printf("%d ", a[i]); //输出排列结果
nation[indexOfPossibility][i] = a[i]; //为每种可能情况赋值
color[indexOfPossibility][i] = a[i];
animal[indexOfPossibility][i] = a[i];
drink[indexOfPossibility][i] = a[i];
cigarette[indexOfPossibility][i] = a[i];
}
//puts(""); //换行
indexOfPossibility++; //转移到下一种可能的情况(从0到119共120种可能情况)
return;
}
for (int i = l; i <= r; i++) {
swap(a[l], a[i]); //递归调用,并且缩小了范围
perm(l + 1, r);
swap(a[l], a[i]);
}
}
int main()
{
for (int i = 0; i < 5; i++)
a[i] = i;
perm(0, 4); //使用排列算法为各种可能情况初始化
/*
for(int i=0;i<120;++i){
for(int j=0;j<5;++j){
cout<<cigarette[i][j]<<" ";
}
cout<<endl;
}
*/
int score = 0;
cout<<"-----------------------------BEGIN------------------------------"<<endl;
for(int i=0;i<120;++i){ //循环nation,依此得到穷举出各种排列情况
for(int j=0;j<120;++j){ //循环color
for(int k=0;k<120;++k){ //循环animal
for(int l=0;l<120;++l){ //循环drink
for(int m=0;m<120;++m){ //循环cigarette
for(int n=0;n<5;++n){ //要找到谁国籍是英国或者养什么宠物
if(nation[i][n]==0){ //条件一:英国人住在红房子里,如果是英国
if(color[j][n]==0){ //如果是红色
score++; //使用自创的积分模式,累计得分
}
}
if(nation[i][n]==1){ //条件二:西班牙人喜欢养狗
if(animal[k][n]==0){
score++;
}
}
if(color[j][n]==1){ //条件三:绿房子的主人喜欢喝咖啡
if(drink[l][n]==0){
score++;
}
}
if(nation[i][n]==2){ //条件四:乌克兰人喜欢喝茶
if(drink[l][n]==1){
score++;
}
}
if(color[j][n]==2){ //条件五:绿房子在白房子的右边
if(n+1<=4 && color[j][n+1]==1){
score++;
}
}
if(cigarette[m][n]==0){ //条件六:抽“万宝路”牌香烟的人养蜗牛
if(animal[k][n]==1){
score++;
}
}
if(color[j][n]==3){ //条件七:黄房子的主人抽“可乐”牌香烟
if(cigarette[m][n]==2){
score++;
}
}
if(n==2){ //条件八:当中那幢房子的主人喝牛奶
if(drink[l][n]==2){
score++;
}
}
if(nation[i][n]==3){ //条件九:挪威人住在左边第一幢房子
if(n==0){
score++;
}
}
if(cigarette[m][n]==1){ //条件十:抽“本生”牌香烟的人和养狐狸的人是隔壁邻居
if(n-1>=0 && animal[k][n-1]==2){
score++;
}
if(n+1<=4 && animal[k][n+1]==2){
score++;
}
}
if(cigarette[m][n]==2){ //条件十一:抽“可乐”牌香烟的人和养马的人是隔壁邻居
if(n-1>=0 && animal[k][n-1]==3){
score++;
}
if(n+1<=4 && animal[k][n+1]==3){
score++;
}
}
if(cigarette[m][n]==3){ //条件十二:抽“肯特”牌香烟的人喝橘子水
if(drink[l][n]==3){
score++;
}
}
if(nation[i][n]==4){ //条件十三:日本人抽“摩尔”牌香烟
if(cigarette[m][n]==4){
score++;
}
}
if(nation[i][n]==3){ //条件十四:挪威人和蓝房子的主人是隔壁邻居
if(n-1>=0 && color[j][n-1]==4){
score++;
}
if(n+1<=4 && color[j][n+1]==4){
score++;
}
}
}
if(score==14){ //如果14种条件都满足则为所求的情况
cout<<"Bingo!!"<<endl;
for(int x=0;x<5;++x){ //输出这种情况的具体值
cout<<nation[i][x]<<" ";
}
cout<<endl;
for(int x=0;x<5;++x){
cout<<color[j][x]<<" ";
}
cout<<endl;
for(int x=0;x<5;++x){
cout<<animal[k][x]<<" ";
}
cout<<endl;
for(int x=0;x<5;++x){
cout<<drink[l][x]<<" ";
}
cout<<endl;
for(int x=0;x<5;++x){
cout<<cigarette[m][x]<<" ";
}
cout<<endl;
}else{ //只要拿不到14分则重置为0重新开始判断下一种情况
score=0;
}
}
}
}
}
}
cout<<"----------------------------END---------------------------"<<endl;
}