“积分模式”应用 —— “爱因斯坦大难题”代码实现


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;

}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值