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()函數。

綜合這些條件,我們就可以將計算量進一步壓縮,從而可以在短時間內解決問題了!



發佈了18 篇原創文章 · 獲贊 53 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章