C#解號稱愛因斯坦出的智力題

導讀:
  現有題號稱愛因斯坦出的智力題全世界只有2%能夠做出。
  ------------------------------------------------
  1、在一條街上,有5座房子,噴了5種顏色。
  2、每個房裏住着不同國籍的人
  3、每個人喝不同的飲料,抽不同品牌的香菸,養不同的寵物
  問題是:誰養魚?
  提示:
  1、英國人住紅色房子
  2、瑞典人養狗
  3、丹麥人喝茶
  4、綠色房子在白色房子左面
  5、綠色房子主人喝咖啡
  6、抽Pall Mall 香菸的人養鳥
  7、黃色房子主人抽Dunhill 香菸
  8、住在中間房子的人喝牛奶
  9、 挪威人住第一間房
  10、抽Blends香菸的人住在養貓的人隔壁
  11、養馬的人住抽Dunhill 香菸的人隔壁
  12、抽Blue Master的人喝啤酒
  13、德國人抽Prince香菸
  14、挪威人住藍色房子隔壁
  15、抽Blends香菸的人有一個喝水的鄰居
  ---------------------------------------
  這裏我想講的是通過暴力算法窮舉所有可能讓計算機進行求解。
  第一次試驗使用“純暴力”解法。問題規模達到(5!=120)5次冪,大於10G。本人花了將近30分鐘運行,計算機依然沒有算出結果。估計就是算一天也未必能結束。
  於是在第二次試驗中該進算法,通過使用類似邏輯中“短路”(如:a&&b&&c當a爲假時b,c可以不需要計算結果也爲假)的生成算法瞬間即可得到結果。
  結論:
  在這次經歷中,我既感到通過寫程序解決實際問題帶來的快樂也進一步感受了算法的重要性。好的算法帶來的效率是十分可觀的。
  說明:
  1根據試驗第四句話的左臨意思包括相鄰,否則解不惟一。
  
  ProTable.cs
  using System;
  using System.Collections.Generic;
  using System.Text;
  namespace SolvePuzzle
  {
  enum 國籍{英國,瑞典,丹麥,挪威,德國};
  enum 顏色 {紅,綠,藍,黃,白};
  enum 寵物 { 鳥,貓,馬,魚,狗};
  enum 飲料 {水,牛奶,咖啡,茶,啤酒};
  enum 香菸 { blends,blue,prince,dunhill,pall};
  public class ProTable
  {
  private const string rule = @"
  1、在一條街上,有5座房子,噴了5種顏色。
  2、每個房裏住着不同國籍的人
  3、每個人喝不同的飲料,抽不同品牌的香菸,養不同的寵物
  問題是:誰養魚?
  提示:
  1、英國人住紅色房子
  2、瑞典人養狗
  3、丹麥人喝茶
  4、綠色房子在白色房子左面
  5、綠色房子主人喝咖啡
  6、抽Pall Mall 香菸的人養鳥
  7、黃色房子主人抽Dunhill 香菸
  8、住在中間房子的人喝牛奶
  9、 挪威人住第一間房
  10、抽Blends香菸的人住在養貓的人隔壁
  11、養馬的人住抽Dunhill 香菸的人隔壁
  12、抽Blue Master的人喝啤酒
  13、德國人抽Prince香菸
  14、挪威人住藍色房子隔壁
  15、抽Blends香菸的人有一個喝水的鄰居
  ";
  public string Rule { get { return rule; } }
  private enum T{國籍=0,顏色,寵物,飲料,香菸};
  private const int N = 5;
  //求排列
  private static int[,] aid = new int[120, N];
  static ProTable()
  {
  int k = 0;
  for (int i0 = 0; i0   {
  for (int i1 = 0; i1   {
  if (i1 == i0) continue;
  for (int i2 = 0; i2   {
  if (i2 == i1 || i2 == i0) continue;
  for (int i3 = 0; i3   {
  if (i3 == i2 || i3 == i1 || i3 == i0) continue;
  for (int i4 = 0; i4   {
  if (i4 == i3 || i4 == i2 || i4 == i1 || i4 == i0) continue;
  aid[k, 0] = i0;
  aid[k, 1] = i1;
  aid[k, 2] = i2;
  aid[k, 3] = i3;
  aid[k, 4] = i4;
  k++;
  }
  }
  }
  }
  }
  }
  //判斷矩陣
  // 國籍,顏色,寵物,飲料,香菸
  //1
  //2
  //3
  //4
  //5
  private int[,] array = new int[N, N];
  //根據排列數組生成
  private void replace(int i,int j)
  {
  for (int k = 0; k   {
  array[k, i] = aid[j, k];
  }
  }
  //通過getXX得到相應的行號
  private int get香菸(香菸 n)
  {
  for (int i = 0; i   if (array[i, (int)T.香菸] == (int)n)
  return i;
  return -1;
  }
  private int get飲料(飲料 n)
  {
  for (int i = 0; i   if (array[i, (int)T.飲料] == (int)n)
  return i;
  return -1;
  }
  private int get寵物(寵物 n)
  {
  for (int i = 0; i   if (array[i, (int)T.寵物] == (int)n)
  return i;
  return -1;
  }
  private int get國籍(國籍 n)
  {
  for (int i = 0; i   if (array[i, (int)T.國籍] == (int)n)
  return i;
  return -1;
  }
  private int get顏色(顏色 n)
  {
  for (int i = 0; i   if (array[i, (int)T.顏色] == (int)n)
  return i;
  return -1;
  }
  //規則:
  //1、英國人住紅色房子
  //2、瑞典人養狗
  //3、丹麥人喝茶
  //4、綠色房子在白色房子左面
  //5、綠色房子主人喝咖啡
  //6、抽Pall Mall 香菸的人養鳥
  //7、黃色房子主人抽Dunhill 香菸
  //8、住在中間房子的人喝牛奶
  //9、 挪威人住第一間房
  //10、抽Blends香菸的人住在養貓的人隔壁
  //11、養馬的人住抽Dunhill 香菸的人隔壁
  //12、抽Blue Master的人喝啤酒
  //13、德國人抽Prince香菸
  //14、挪威人住藍色房子隔壁
  //15、抽Blends香菸的人有一個喝水的鄰居
  //1、英國人住紅色房子
  private bool assert1()
  {
  if (!(
  array[get國籍(國籍.英國), (int)T.顏色] == (int)顏色.紅
  ))
  return false;
  return true;
  }
  //2、瑞典人養狗
  private bool assert2()
  {
  if (!(
  array[get國籍(國籍.瑞典), (int)T.寵物] == (int)寵物.狗
  ))
  return false;
  
  return true;
  }
  //3、丹麥人喝茶
  private bool assert3()
  {
  if (!(
  array[get國籍(國籍.丹麥), (int)T.飲料] == (int)飲料.茶
  ))
  return false;
  
  return true;
  }
  //4、綠色房子在白色房子左面
  private bool assert4()
  {
  if (!(
  get顏色(顏色.綠) == (get顏色(顏色.白) - 1) //另一種理解get顏色(顏色.綠)   ))
  return false;
  
  return true;
  }
  //5、綠色房子主人喝咖啡
  private bool assert5()
  {
  if (!(
  array[get顏色(顏色.綠), (int)T.飲料] == (int)飲料.咖啡
  ))
  return false;
  
  return true;
  }
  //6、抽Pall Mall 香菸的人養鳥
  private bool assert6()
  {
  if (!(
  array[get香菸(香菸.pall), (int)T.寵物] == (int)寵物.鳥
  ))
  return false;
  
  return true;
  }
  //7、黃色房子主人抽Dunhill 香菸
  private bool assert7()
  {
  if (!(
  array[get顏色(顏色.黃), (int)T.香菸] == (int)香菸.dunhill
  ))
  return false;
  
  return true;
  }
  //8、住在中間房子的人喝牛奶
  private bool assert8()
  {
  if (!(
  array[2, (int)T.飲料] == (int)飲料.牛奶
  ))
  return false;
  return true;
  }
  //9、 挪威人住第一間房
  private bool assert9()
  {
  int i = get國籍(國籍.挪威);
  if (!(
  i== 0||i==4
  ))
  return false;
  
  return true;
  }
  //10、抽Blends香菸的人住在養貓的人隔壁
  private bool assert10()
  {
  int t1 = get香菸(香菸.blends), t2 = get寵物(寵物.貓);
  if (!(
  t1 == (t2 + 1) || t1 == (t2 - 1)
  ))
  return false;
  
  return true;
  }
  //11、養馬的人住抽Dunhill 香菸的人隔壁
  private bool assert11()
  {
  int t1 = get寵物(寵物.馬);
  int t2 = get香菸(香菸.dunhill);
  if (!(
  t1 == (t2 + 1) || t1 == (t2 - 1)
  ))
  return false;
  return true;
  }
  //12、抽Blue Master的人喝啤酒
  private bool assert12()
  {
  if (!(
  array[get香菸(香菸.blue), (int)T.飲料] == (int)飲料.啤酒
  ))
  return false;
  
  return true;
  }
  //13、德國人抽Prince香菸
  private bool assert13()
  {
  if (!(
  array[get國籍(國籍.德國), (int)T.香菸] == (int)香菸.prince
  ))
  return false;
  
  return true;
  }
  //14、挪威人住藍色房子隔壁
  private bool assert14()
  {
  int t1 = get國籍(國籍.挪威);
  int t2 = get顏色(顏色.藍);
  if (!(
  t1 == (t2 + 1) || t1 == (t2 - 1)
  ))
  return false;
  
  return true;
  }
  //15、抽Blends香菸的人有一個喝水的鄰居
  private bool assert15()
  {
  int t1 = get香菸(香菸.blends);
  int t2 = get飲料(飲料.水);
  if (!(
  t1 == (t2 + 1) || t1 == (t2 - 1)
  ))
  return false;
  return true;
  }
  private bool assert()
  {
  return assert1() &&assert2() &&assert3() &&assert4() &&assert5() &&assert6() &&assert7() &&assert8() &&assert9() &&
  assert10() &&assert11() &&assert12() &&assert13() &&assert14() &&assert15();
  }
  /*純暴力算法以作比較
  public void Solve_()
  {
  for (int i0 = 0; i0   {
  replace(0, i0);
  for (int i1 = 0; i1   {
  replace(1, i1);
  for (int i2 = 0; i2   {
  replace(2, i2);
  for (int i3 = 0; i3   {
  replace(3, i3);
  for (int i4 = 0; i4   {
  replace(4, i4);
  if (assert())
  {
  Console.WriteLine(this);
  }
  }
  }
  }
  }
  }
  }
  */
  public void Solve()
  {
  //解號
  int sn = 1;
  
  //逐步生成判別表的算法
  for (int i0 = 0; i0   {
  replace((int)T.國籍, i0);
  if (!assert9())
  continue;
  for (int i1 = 0; i1   {
  replace((int)T.飲料, i1);
  if (!assert8())
  continue;
  if (!(assert3()))
  continue;
  for (int i2 = 0; i2   {
  replace((int)T.顏色, i2);
  if (!assert4())
  continue;
  if (!(assert1() &&assert14()&&assert5()))
  continue;
  for (int i3 = 0; i3   {
  replace((int)T.寵物, i3);
  if (!(assert2()))
  continue;
  for (int i4 = 0; i4   {
  replace((int)T.香菸, i4);
  if (!(assert6() &&assert7() &&assert10() &&assert11() &&assert12() &&assert15() &&assert13()))
  continue;
  if (assert())
  {
  Console.WriteLine("解:"+sn++);
  Console.WriteLine(this);
  }
  }
  }
  }
  }
  }
  }
  //國籍=0,顏色,寵物,飲料,香菸
  public override string ToString()
  {
  StringBuilder sb = new StringBuilder();
  for (int i = 0; i <5; i++)
  {
  sb.Append((i+1).ToString()+": ");
  sb.Append(Enum.GetName(typeof(國籍),array[i,(int)T.國籍])+", ");
  sb.Append(Enum.GetName(typeof(顏色), array[i, (int)T.顏色]) + ", ");
  sb.Append(Enum.GetName(typeof(寵物), array[i, (int)T.寵物]) + ", ");
  sb.Append(Enum.GetName(typeof(飲料), array[i, (int)T.飲料]) + ", ");
  sb.Append(Enum.GetName(typeof(香菸), array[i, (int)T.香菸]) + "/n");
  }
  return sb.ToString();
  }
  }
  }
  -------------------------
  Program.cs
  using System;
  using System.Collections.Generic;
  using System.Text;
  namespace SolvePuzzle
  {
  class Program
  {
  static void Main(string[] args)
  {
  ProTable t = new ProTable();
  t.Solve();
  }
  }
  }
  
  
  Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1539677

本文轉自
http://blog.csdn.net/21aspnet/archive/2007/03/24/1539677.aspx
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章