您的位置:首页 > 编程语言 > C#

C#编程解决类似爱因斯坦智力题的问题

2013-12-15 22:11 441 查看
题目:

有五座房子,每座房子的颜色不同,里面分别住着不同国家的人,每个人都有自己养的不同宠物喜欢喝的不同饮料、抽的不同牌子的烟。现已知以下一些信息:

英国人住在红色的房子里 ;

西班牙人养了一条狗;

挪威人住在左边的第一个房子里;
黄房子里的人喜欢抽kools牌的香烟;

抽chesterfields牌香烟的人与养狐狸的人是邻居;

挪威人住在蓝色房子旁边;

抽winston牌香烟的人养了一个蜗牛;

抽lucky strike牌香烟的人喜欢喝橘子汁;

乌克兰人喜欢喝茶;

日本人抽parlianments牌的烟;

抽kools牌香烟的人与养马的人是邻居;

喜欢喝咖啡的人住在绿房子里;

绿房子在象牙白房子的右边;

中间那个房子里的人喜欢喝牛奶。

根据以上条件,请你判断哪个房子里的人养斑马?哪个房子里的人喜欢喝水?最后把所有的东西对号入座。

一开始想法很简单,直接暴力破解,于是有了这个算法的雏形,不过稍微计算一下后发现,244883200000种组合跑起来怕不是一时半会能出结果的……于是不停改进算法,最后终于发现一个真理:一条判断胜过千万次的运算

(多么痛苦的领悟!),这个程序告诉我们决策的重要性

程序运行结果如下:



先上代码:

//有五座房子,每座房子的颜色不同,里面分别住着不同国家的人,每个人都有自己养的不同宠物、
//喜欢喝的不同饮料、抽的不同牌子的烟。现已知以下一些信息:
//英国人住在红色的房子里;
//西班牙人养了一条狗;*
//挪威人住在左边的第一个房子里;
//黄房子里的人喜欢抽kools牌的香烟;*
//抽chesterfields牌香烟的人与养狐狸的人是邻居;*
//挪威人住在蓝色房子旁边;
//抽winston牌香烟的人养了一个蜗牛;*
//抽lucky strike牌香烟的人喜欢喝橘子汁;*
//乌克兰人喜欢喝茶;*
//日本人抽parlianments牌的烟;*
//抽kools牌香烟的人与养马的人是邻居;*
//喜欢喝咖啡的人住在绿房子里;
//绿房子在象牙白房子的右边;
//中间那个房子里的人喜欢喝牛奶。
//根据以上条件,请你判断哪个房子里的人养斑马?哪个房子里的人喜欢喝水?最后把所有的东西对号入座。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace 爱因斯坦智力题暴力破解
{
class Program
{
static DateTime t1=new DateTime();
static DateTime t2 = new DateTime();
static void Main(string[] args)
{
//被计时的代码段
t1 = DateTime.Now;
Start s = new Start();
Start.h1();
t2 = DateTime.Now;
//
Console.WriteLine("\n耗时: {0} 秒", (t2 - t1).TotalSeconds);
Console.ReadKey(true);
}
}
public class Start
{
static Person[] persons;
static int contains = 0;
static bool[] Isbuild;
public Start()
{
persons = new Person[7];//实际使用1~5,0和6用来作相邻判断时防止数组越界
persons[0] = new Person();
persons[6] = new Person();
Isbuild = new bool[5] { false, false, false, false, false };
}
//组装第一间房子(左数第一间)
public static bool h1()
{
for (int h = 1; h <= 5; h++)
for (int p = 1; p <= 5; p++)
for (int d = 1; d <= 5; d++)
for (int s = 1; s <= 5; s++)
{
persons[1] = new Person(h, 3, p, d, s);//挪威人住在左边的第一个房子里;
if (!Isbuild[0])
{
Isbuild[0] = true;
contains++;
}
//第一间房子不是红色、蓝色、白色,也不喝牛奶,茶,不抽parlianments,不养狗(额,后面几个都注释后才发现类似下面的判断加不加都无所谓,速度上只是0.1s的差距)
//if (persons[1] .housecolor != HouseColor.红色 && persons[1] .housecolor != HouseColor.蓝色 && persons[1] .housecolor != HouseColor.白色 && persons[1] .drink != Drink.牛奶 && persons[1] .drink != Drink.茶&&persons[1] .pet!=Pet.狗&&persons[1] .smoke!=Smoke.parlianments)
if (term())
{
if (!h2())
continue;
}
}
return false;
}
//组装第二间房子
public static bool h2()
{
for (int c = 1; c <= 5; c++)
for (int p = 1; p <= 5; p++)
for (int d = 1; d <= 5; d++)
for (int s = 1; s <= 5; s++)
{
persons[2] = new Person(5, c, p, d, s);//第二间房子是蓝色的
if (!Isbuild[1])
{
Isbuild[1] = true;
contains++;
}
if (persons[2] .Equals(persons[1] ))
continue;
//第二间房子不住挪威人、英国人,不喝咖啡、牛奶,不抽kools的烟
//if (persons[2] .country != Country.挪威 && persons[2] .country != Country.英国 && persons[2] .drink != Drink.咖啡 && persons[2] .drink != Drink.牛奶 && persons[2] .smoke != Smoke.kools)
if (term())
{
if (!h3())
continue;
}
}
persons[2]  = new Person(0, 0, 0, 0, 0);
Isbuild[1] = false;
contains--;
return false;
}
//组装第三间房子
public static bool h3()
{
for (int h = 1; h <= 5; h++)
for (int c = 1; c <= 5; c++)
for (int p = 1; p <= 5; p++)
for (int s = 1; s <= 5; s++)
{
persons[3]  = new Person(h, c, p, 2, s);//中间房子的人喝牛奶
if (!Isbuild[2])
{
Isbuild[2] = true;
contains++;
}
if (persons[3] .Equals(persons[2] )|| persons[3] .Equals(persons[1] ))
continue;
//第三间房自不是绿色、蓝色,不住乌克兰人,不住挪威人,不抽lucky strike的烟
//if (persons[3] .housecolor != HouseColor.绿色 && persons[3] .housecolor != HouseColor.蓝色 && persons[3] .country != Country.乌克兰 && persons[3] .country != Country.挪威&& persons[3] .smoke != Smoke.lucky_strike)
if (term())
{
if (!h4())
continue;
}
}
persons[3]  = new Person(0, 0, 0, 0, 0);
Isbuild[2] = false;
contains--;
return false;
}
//组装第四间房子
public static bool h4()
{
for (int h = 1; h <= 5; h++)
for (int c = 1; c <= 5; c++)
for (int p = 1; p <= 5; p++)
for (int d = 1; d <= 5; d++)
for (int s = 1; s <= 5; s++)
{
persons[4] = new Person(h, c, p, d, s);//第四间房子
if (!Isbuild[3])
{
Isbuild[3] = true;
contains++;
}
if (persons[4] .Equals(persons[3] ) || persons[4] .Equals(persons[2] ) || persons[4] .Equals(persons[1] ))
continue;
//第四间房子不是蓝色、红色、黄色,不住挪威人,不喝牛奶
//if (persons[4] .housecolor != HouseColor.蓝色 && persons[4] .housecolor != HouseColor.红色 && persons[4] .housecolor != HouseColor.黄色 && persons[4] .country != Country.挪威 && persons[4] .drink != Drink.牛奶)
if (term())
{
if (!h5())
continue;
}
}
persons[4] = new Person(0, 0, 0, 0, 0);
Isbuild[3] = false;
contains--;
return false;
}
//组装第五间房子
public static bool h5()
{
for (int h = 1; h <= 5; h++)
for (int c = 1; c <= 5; c++)
for (int p = 1; p <= 5; p++)
for (int d = 1; d <= 5; d++)
for (int s = 1; s <= 5; s++)
{
persons[5] = new Person(h, c, p, d, s);//第五间房子
if (!Isbuild[4])
{
Isbuild[4] = true;
contains++;
}
if (persons[5].Equals(persons[4] ) || persons[5].Equals(persons[3] ) || persons[5].Equals(persons[2] ) || persons[5].Equals(persons[1] ))
continue;
//第五间房子不是蓝色、白色,不住挪威人,不喝牛奶
//if (persons[5].housecolor != HouseColor.蓝色 && persons[5].housecolor != HouseColor.白色 && persons[5].country != Country.挪威 && persons[5].drink != Drink.牛奶)
test();
}
persons[5] = new Person(0,0,0,0,0);
Isbuild[4] = false;
contains--;
return false;
}

public static bool term()
{
for (int i = 1; i <= contains ; i++)
if (persons[i].country == Country.英国 && persons[i].housecolor != HouseColor.红色 || persons[i].country != Country.英国 && persons[i].housecolor == HouseColor.红色)
return false;
for (int i =1; i <=contains; i++)
if (persons[i].country == Country.乌克兰 && persons[i].drink != Drink.茶||persons[i].country != Country.乌克兰 && persons[i].drink == Drink.茶)
return false;
for (int j =1; j <=contains ; j++)
if (persons[j].country == Country.西班牙 && persons[j].pet != Pet.狗 || persons[j].country != Country.西班牙 && persons[j].pet == Pet.狗)
return false;
for (int k = 1; k <=contains ; k++)
if (persons[k].housecolor == HouseColor.黄色 && persons[k].smoke != Smoke.kools || persons[k].housecolor != HouseColor.黄色 && persons[k].smoke == Smoke.kools)
return false;
for (int x = 1; x <=contains ; x++)
if (persons[x].pet == Pet.蜗牛 && persons[x].smoke != Smoke.winston || persons[x].pet != Pet.蜗牛 && persons[x].smoke == Smoke.winston)
return false;
for (int y = 1; y <=contains ; y++)
if (persons[y].drink == Drink.橘子汁 && persons[y].smoke != Smoke.lucky_strike || persons[y].drink != Drink.橘子汁 && persons[y].smoke == Smoke.lucky_strike)
return false;
for (int z = 1; z <=contains; z++)
if (persons[z].country == Country.日本 && persons[z].smoke != Smoke.parlianments || persons[z].country != Country.日本 && persons[z].smoke == Smoke.parlianments)
return false;
for (int l = 1; l <=contains; l++)
if (persons[l].housecolor == HouseColor.绿色 && persons[l].drink != Drink.咖啡 || persons[l].housecolor != HouseColor.绿色 && persons[l].drink == Drink.咖啡)
return false;
return true;
}
public static void test()
{
if(test_1()&&test_2()&&test_3())
{
ShowResult();
Anwser();
}
}
public static bool test_1()//已给定的二维条件4/8
{
for (int m = 1; m <= contains ; m++)
if (persons[m].country == Country.英国 && persons[m].housecolor == HouseColor.红色)//英国人住在红色的房子里;
for (int i = 1; i <= contains ; i++)
if (persons[i].country == Country.乌克兰 && persons[i].drink == Drink.茶)//乌克兰人喜欢喝茶;
for (int j = 1; j <= contains ; j++)
if (persons[j].country == Country.西班牙 && persons[j].pet == Pet.狗)//西班牙人养了一条狗;
for (int k = 1; k <= contains ; k++)
if (persons[k].housecolor == HouseColor.黄色 && persons[k].smoke == Smoke.kools)//黄房子里的人喜欢抽kools牌的香烟;
return true;
return false;
}
public static bool test_2()//已给定的二维条件4/8
{
for (int x = 1; x <= contains ; x++)
if (persons[x].pet == Pet.蜗牛 && persons[x].smoke == Smoke.winston)//抽winston牌香烟的人养了一个蜗牛;
for (int y = 1; y <= contains ; y++)
if (persons[y].drink == Drink.橘子汁 && persons[y].smoke == Smoke.lucky_strike)//抽lucky strike牌香烟的人喜欢喝橘子汁;
for (int z = 1; z <= contains ; z++)
if (persons[z].country == Country.日本 && persons[z].smoke == Smoke.parlianments)//日本人抽parlianments牌的烟;
for (int l = 1; l <= contains ; l++)
if (persons[l].housecolor == HouseColor.绿色 && persons[l].drink == Drink.咖啡)//喜欢喝咖啡的人住在绿房子里;
return true;
return false;
}
public static bool test_3()//相邻位置判断条件3/3
{
for (int k = 1; k <= contains; k++)
if (persons[k].housecolor == HouseColor.白色 && persons[(k + 1) % 6].housecolor == HouseColor.绿色)//绿房子在象牙白房子的右边;
for (int i = 1; i <= contains; i++)
if (persons[i].pet == Pet.狐狸 && persons[i - 1].smoke == Smoke.chesterfields || persons[i].pet == Pet.狐狸 && persons[(i + 1) % 6].smoke == Smoke.chesterfields)//抽chesterfields牌香烟的人与养狐狸的人是邻居;
for (int j = 1; j <= contains; j++)
if (persons[j].smoke == Smoke.kools && persons[j - 1].pet == Pet.马 || persons[j].smoke == Smoke.kools && persons[(j + 1) % 6].pet == Pet.马)//抽kools牌香烟的人与养马的人是邻居;
return true;
return false;
}
public static void ShowResult()
{
for (int n = 1; n <= 5; n++)
Console.WriteLine(persons
);
Console.WriteLine("---------------------------------");
}
public static void Anwser()
{
Console.WriteLine("答案是:");
for (int i = 1; i <= 5; i++)
if (persons[i].drink == Drink.水)
Console.WriteLine("    {0}人喝{1}", persons[i].country, persons[i].drink);
for (int i = 1; i <= 5; i++)
if (persons[i].pet == Pet.斑马)
Console.WriteLine("    {0}人养{1}",persons[i].country,persons[i].pet);
}
}
public enum HouseColor { 红色 = 1, 白色, 黄色, 绿色, 蓝色 }
public enum Country { 英国 = 1, 西班牙, 挪威, 乌克兰, 日本 }
public enum Pet { 狐狸 = 1, 狗, 蜗牛, 马, 斑马 }
public enum Drink { 咖啡 = 1, 牛奶, 水, 茶, 橘子汁 }
public enum Smoke { kools = 1, chesterfields, winston, lucky_strike, parlianments }
public class Person
{
public HouseColor housecolor;
public Country country;
public Pet pet;
public Drink drink;
public Smoke smoke;
public bool[] avaliable;
public Person(int h, int c, int p, int d, int s)
{
avaliable = new bool[6] { false, false, false, false, false, false };
switch (h)
{
case 0:
break;
case 1:
housecolor = HouseColor.红色;
break;
case 2:
housecolor = HouseColor.白色;
break;
case 3:
housecolor = HouseColor.黄色;
break;
case 4:
housecolor = HouseColor.绿色;
break;
case 5:
housecolor = HouseColor.蓝色;
break;
}
switch (c)
{

case 0:
break;
case 1:
country = Country.英国;
break;
case 2:
country = Country.西班牙;
break;
case 3:
country = Country.挪威;
break;
case 4:
country = Country.乌克兰;
break;
case 5:
country = Country.日本;
break;
}
switch (p)
{

case 0:
break;
case 1:
pet = Pet.狐狸;
break;
case 2:
pet = Pet.狗;
break;
case 3:
pet = Pet.蜗牛;
break;
case 4:
pet = Pet.马;
break;
case 5:
pet = Pet.斑马;
break;
}
switch (d)
{

case 0:
break;
case 1:
drink = Drink.咖啡;
break;
case 2:
drink = Drink.牛奶;
break;
case 3:
drink = Drink.水;
break;
case 4:
drink = Drink.茶;
break;
case 5:
drink = Drink.橘子汁;
break;
}
switch (s)
{
case 0:
break;
case 1:
smoke = Smoke.kools;
break;
case 2:
smoke = Smoke.chesterfields;
break;
case 3:
smoke = Smoke.winston;
break;
case 4:
smoke = Smoke.lucky_strike;
break;
case 5:
smoke = Smoke.parlianments;
break;
}
}
public Person()
{
avaliable = new bool[6] { false, false, false, false, false, false };
}
public Person(Person p)
{
housecolor = p.housecolor;
country = p.country;
pet = p.pet;
drink = p.drink;
smoke = p.smoke;
avaliable = p.avaliable;
}
public override bool Equals(object obj)//只要有部分元素相等则返回真,非全等
{
if (housecolor == ((Person)obj).housecolor || country == ((Person)obj).country || pet == ((Person)obj).pet || drink == ((Person)obj).drink || smoke == ((Person)obj).smoke)
return true;
return false;
}
public override string ToString()
{
string s = housecolor + "  " + country + "  " + pet + "  " + drink + "  " + smoke + "  ";
return s;
}
}
}

好吧,我知道你们不喜欢看代码╮(╯▽╰)╭,下面讲一讲这个问题的解决思路:

首先,因为是第一次碰到这样的问题,你不能假定这个问题的答案只有一个(那样的话程序半路就可以得出答案了),从百度的结果来看呢,有人说是4个,也有说是7个的,不过这种题目有很多变种的,我们不能确定它是不是只有唯一的答案(本题的答案是唯一的哦),所有的可能都必须过一遍。

那么,要想节省时间,就必须把所有不可能的情况提前过滤掉。从问题的规模来看244883200000=(5!)^5,这是考虑所有排列组合的情况下最小的结果,按照先选第一所房子的颜色,再选第二所房子的颜色……再选第五所房子的颜色,然后选第一所房子主人的国籍……………………………………显然,这是正常的思路╮( ̄▽ ̄")╭ 

But,正常思路很显然无法在短时间内解决这个问题,所以,让我们来点非正常的思路吧:继续扩大问题的规模!(疯了!)

没错!将问题的规模扩大至5^5^5=3125^5=298023223876953125再来看,刚才是2400亿种情况,现在是光零头就有8千万亿种情况

,也许你不相信,你可以拿计算器按一下。。。(这可是25个5在相乘)

淡定!先不要惊慌

,我们来看看这个结果是怎么出现的。这次,我们先不考虑条件限制,即所有房子的颜色,国籍,宠物,饮料,香烟都可以在五种给定的条件中任选,允许相同(即五所房子可能都是绿色等等),这样,每生成一所房子就有3125种可能的情况,我们按从左到右的顺序依次生成每所房子,这个时候再来考虑条件问题,不满足则舍弃,满足则继续往右生成。

那么,为什么规模扩大到这么大,反而速度变快了呢?

我们再来分析一下:首先,假设你已经设计了一套方案,方案中第一所房子是给英国人住的,但是根据条件,第一所房子里住的必须是挪威人,所以紧跟着后面的四所房子的方案都被否决了,也就是说共有4^5^5=1125899906842624种不可能的情况被否决了。1125万亿!

再假设,你的第一所房子的方案满足了条件,但是第二所房子的颜色不是蓝色的,所以,后面的三所房子的方案被否决了,否决量是3^5^5=847288609443,共计8000万种可能的情况。

依此类推,到第三所房子,否决量是2^5^5=33554432,3300万!第四所是1^5^5=3125!最后一所房子每次否决量为1。

所以,每当我们完全确定一个条件的时候,无形之中,就有成千上万亿次的计算量被省略了,例如,当确定第一所房子的主人是挪威人的时候,那么这所房子的3125种情况中就有5^5-5^4=2500种情况被排除,应用上面的分析,总共即2500*1125万亿=28亿亿的计算量节省下来了(总数是29亿亿),再加上往后每所房子都有确定的条件:如第二所房子是蓝色的,中间房子的人喝牛奶等等,依次省略计算量为2500*8000万=2000亿,2500*3000万=750亿……

这样做下来,剩余的计算量大概还剩下7000亿左右,依旧是比刚开始的2400亿的计算量要多,但是别忘记了,我们还只是用了所给的条件的一部分,上面忘了提了,题目中所给条件大致可以分为三个类型:确定型(根据描述可以完全判定某项属性的位置)、二维关系型(由二元关系组成)、位置关系型(由位置关系组成)。

对总共给定点的14个条件分类如下:

确定型:

挪威人住在左边的第一个房子里;
挪威人住在蓝色房子旁边;
中间那个房子里的人喜欢喝牛奶。

二维关系型:
英国人住在红色的房子里;
西班牙人养了一条狗;
黄房子里的人喜欢抽kools牌的香烟;
抽winston牌香烟的人养了一个蜗牛;
抽lucky strike牌香烟的人喜欢喝橘子汁;
乌克兰人喜欢喝茶;
日本人抽parlianments牌的烟;
喜欢喝咖啡的人住在绿房子里;

位置关系型:

抽chesterfields牌香烟的人与养狐狸的人是邻居;
抽kools牌香烟的人与养马的人是邻居;
绿房子在象牙白房子的右边;

刚刚我们只是用到了确定型中的三个条件,而剩余还有11个条件是我们还没有用到的。因此,进一步减少计算量就需要对这些条件进行判断也就是程序中的test_1()、test_2()和test_3()函数。

综合这些条件,我们就可以将计算量进一步压缩,从而可以在短时间内解决问题了!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐