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

题目:

有五座房子,每座房子的颜色不同,里面分别住着不同国家的人,每个人都有自己养的不同宠物喜欢喝的不同饮料、抽的不同牌子的烟。现已知以下一些信息:
英国人住在红色的房子里 ;
西班牙人养了一条狗;
挪威人住在左边的第一个房子里;
黄房子里的人喜欢抽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[n]);
          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个条件分类如下:

  • 确定型:
  1. 挪威人住在左边的第一个房子里;
  2. 挪威人住在蓝色房子旁边;
  3. 中间那个房子里的人喜欢喝牛奶。
  • 二维关系型:
    1. 英国人住在红色的房子里;
    2. 西班牙人养了一条狗;
    3. 黄房子里的人喜欢抽kools牌的香烟;
    4. 抽winston牌香烟的人养了一个蜗牛;
    5. 抽lucky strike牌香烟的人喜欢喝橘子汁;
    6. 乌克兰人喜欢喝茶;
    7. 日本人抽parlianments牌的烟;
    8. 喜欢喝咖啡的人住在绿房子里;
  • 位置关系型:
  1. 抽chesterfields牌香烟的人与养狐狸的人是邻居;
  2. 抽kools牌香烟的人与养马的人是邻居;
  3. 绿房子在象牙白房子的右边;

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

综合这些条件,我们就可以将计算量进一步压缩,从而可以在短时间内解决问题了!



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值