最近看到一個比較老的題目,題目----在一條街上,有5座房子,噴了5種顏色,每個房里住着不同國籍的人,每個人喝不同的飲料,抽不同品牌的香煙,養不同的寵物,問題---誰養魚?
以前沒事還做過這個題,現在寫個代碼實現一下,還是感覺還是挺有意思的,先來看下推導條件吧:
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選擇確定條件和不確定條件:

不確定條件: 4.綠色房子在白色房子左面 ; 8.住在中間房子的人喝牛奶 ; 9. 挪威人住第一間房; 10.抽Blends香煙的人住在養貓的人隔壁;11.養馬的人住抽Dunhill 香煙的人隔壁 ; 14.挪威人住藍色房子隔壁 ;15.抽Blends香煙的人有一個喝水的鄰居
(特別說明:條件9和14算是確定條件,一號房是挪威人住,二號房是藍色,不用畫圖,也不用推導,直接可以得出的結論,放在不確定里面是因為不好在確定條件里面展示)
2.條件推導
推導的步驟 8,9,14(二號房是藍色)→4,5(四號房是綠色,五號房是白色)→1,7(一號房是黃色,三號房是紅色)→11(二號房養馬),最后推導出的結果圖如下:

3.這個時候剩下的條件:2,3,6,10,12,13,15,自己推導的時候在這里困擾了一下,像填字游戲一樣,條件怎么弄進去感覺都是對的,觀察了最后剩下的三種飲料:啤酒, 茶,水,而且給出的條件比較多,3,12,15,條件3丹麥人喝茶,適用范圍是二號房和五號房,假設丹麥人是五號房(走不通),丹麥人是二號房,接下來的事情就比較容易推導.(3,12,10,15,13,2,6==本人按照這個順序推導的)

程序推導
1.根據題目,創建一個包含房號,國家,顏色,飲料,寵物,香煙的Person類:
public class Person
{
//房號
public int Position { get; set; }
//國家
public string Country { get; set; }
//房子顏色
public string Color { get; set; }
//飲料
public string Drink { get; set; }
//香煙
public string Cigarette { get; set; }
//寵物
public string Animal { get; set; }
}
2.去除所有的確定選項:
int[] indexArr = new int[] { 1, 2, 3, 4, 5 };
string[] countryArr = new string[] { "瑞典", "德國", "英國", "丹麥", "挪威" };
string[] colorArr = new string[] { "黃色", "藍色", "紅色", "綠色", "白色" };
string[] drinkArr = new string[] { "水", "茶", "牛奶", "咖啡", "啤酒" };
string[] cigareteeArr = new string[] { "Pall Mall", "Dunhill", "Blends", "Blue Master", "Prince" };
string[] animalArr = new string[] { "貓", "馬", "鳥", "魚", "狗" };
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
var allData = (from index in indexArr
from country in countryArr
from color in colorArr
from drink in drinkArr
from cigaretee in cigareteeArr
from animal in animalArr
select new Person { Position = index, Country = country, Color = color, Drink = drink, Cigarette = cigaretee, Animal = animal }).ToList();
//1.英國人住紅色房子
allData.RemoveAll(p => p.Country == "英國" && p.Color != "紅色");
allData.RemoveAll(p => p.Country != "英國" && p.Color == "紅色");
// 2.瑞典人養狗
allData.RemoveAll(p => p.Country == "瑞典" && p.Animal != "狗");
allData.RemoveAll(p => p.Country != "瑞典" && p.Animal == "狗");
// 3.丹麥人喝茶
allData.RemoveAll(p => p.Country == "丹麥" && p.Drink != "茶");
allData.RemoveAll(p => p.Country != "丹麥" && p.Drink == "茶");
// 5.綠色房子主人喝咖啡
allData.RemoveAll(p => p.Color == "綠色" && p.Drink != "咖啡");
allData.RemoveAll(p => p.Color != "綠色" && p.Drink == "咖啡");
// 6.抽Pall Mall 香煙的人養鳥
allData.RemoveAll(p => p.Cigarette == "Pall Mall" && p.Animal != "鳥");
allData.RemoveAll(p => p.Cigarette != "Pall Mall" && p.Animal == "鳥");
//7.黃色房子主人抽Dunhill 香煙
allData.RemoveAll(p => p.Color == "黃色" && p.Cigarette != "Dunhill");
allData.RemoveAll(p => p.Color != "黃色" && p.Cigarette == "Dunhill");
//8.挪威人住第一間房
allData.RemoveAll(p => p.Country == "挪威" && p.Position != 1);
allData.RemoveAll(p => p.Country != "挪威" && p.Position == 1);
//9.挪威人住第一間房
allData.RemoveAll(p => p.Drink == "牛奶" && p.Position != 3);
allData.RemoveAll(p => p.Drink != "牛奶" && p.Position == 3);
//12.抽Blue Master的人喝啤酒
allData.RemoveAll(p => p.Drink == "啤酒" && p.Cigarette != "Blue Master");
allData.RemoveAll(p => p.Drink != "啤酒" && p.Cigarette == "Blue Master");
//13.德國人抽Prince香煙
allData.RemoveAll(p => p.Country == "德國" && p.Cigarette != "Prince");
allData.RemoveAll(p => p.Country != "德國" && p.Cigarette == "Prince");
// 14.挪威人住藍色房子隔壁(藍色房子是二號房)
allData.RemoveAll(p => p.Color == "藍色" && p.Position != 2);
allData.RemoveAll(p => p.Color != "藍色" && p.Position == 2);
3.窮舉取出所有的可能的結果集(一組對象,不是一個對象)
var result = (from r1 in allData.Where(item => item.Position == 1)
from r2 in allData.Where(item => item.Position == 2)
from r3 in allData.Where(item => item.Position == 3)
from r4 in allData.Where(item => item.Position == 4)
from r5 in allData.Where(item => item.Position == 5)
where r1.Country != r2.Country && r1.Country != r3.Country && r1.Country != r4.Country && r1.Country != r5.Country &&
r2.Country != r3.Country && r2.Country != r4.Country && r2.Country != r5.Country &&
r3.Country != r4.Country && r3.Country != r5.Country &&
r4.Country != r5.Country &&
r1.Color != r2.Color && r1.Color != r3.Color && r1.Color != r4.Color && r1.Color != r5.Color &&
r2.Color != r3.Color && r2.Color != r4.Color && r2.Color != r5.Color &&
r3.Color != r4.Color && r3.Color != r5.Color &&
r4.Color != r5.Color &&
r1.Drink != r2.Drink && r1.Drink != r3.Drink && r1.Drink != r4.Drink && r1.Drink != r5.Drink &&
r2.Drink != r3.Drink && r2.Drink != r4.Drink && r2.Drink != r5.Drink &&
r3.Drink != r4.Drink && r3.Drink != r5.Drink &&
r4.Drink != r5.Drink &&
r1.Cigarette != r2.Cigarette && r1.Cigarette != r3.Cigarette && r1.Cigarette != r4.Cigarette && r1.Cigarette != r5.Cigarette &&
r2.Cigarette != r3.Cigarette && r2.Cigarette != r4.Cigarette && r2.Cigarette != r5.Cigarette &&
r3.Cigarette != r4.Cigarette && r3.Cigarette != r5.Cigarette &&
r4.Cigarette != r5.Cigarette &&
r1.Animal != r2.Animal && r1.Animal != r3.Animal && r1.Animal != r4.Animal && r1.Animal != r5.Animal &&
r2.Animal != r3.Animal && r2.Animal != r4.Animal && r2.Animal != r5.Animal &&
r3.Animal != r4.Animal && r3.Animal != r5.Animal &&
r4.Animal != r5.Animal
select new List<Person> { r1, r2, r3, r4, r5 }).ToList();
4.按照剩余的條件進行刪除並輸出:
// 4.綠色房子在白色房子左面
//白色房子的房號比綠色的大1
result.RemoveAll(item => 1 != item.Single(m => m.Color == "白色").Position - item.Single(m => m.Color == "綠色").Position);
// 10.抽Blends香煙的人住在養貓的人隔壁
result.RemoveAll(item => 1 != Math.Abs(item.Single(m => m.Cigarette == "Blends").Position - item.Single(m => m.Animal == "貓").Position));
// 11.養馬的人住抽Dunhill 香煙的人隔壁
result.RemoveAll(item => 1 != Math.Abs(item.Single(m => m.Animal == "馬").Position - item.Single(m => m.Cigarette == "Dunhill").Position));
//14.挪威人住藍色房子隔壁(藍色房子是二號房)
//result.RemoveAll(item => 1 != Math.Abs(item.Single(m => m.Country == "挪威").Position - item.Single(m => m.Color == "藍色").Position));
//15.抽Blends香煙的人有一個喝水的鄰居
result.RemoveAll(item => 1 != Math.Abs(item.Single(m => m.Cigarette == "Blends").Position - item.Single(m => m.Drink == "水").Position));
var person = result.Select(item => item.Single(m => m.Animal == "魚")).First();
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
Console.WriteLine("{0},時間:{1}", person.Country, elapsedTime.ToString());
Console.WriteLine("編號\0\0國家\0\0顏色\0\0飲料\0\0寵物\0\0香煙");
foreach (var item in result)
{
foreach (Person data in item)
{
if (data.Position == 1 || data.Position == 2)
{
Console.WriteLine("\0{0}\0\0\0\0{1}\0\0{2}\0\0{3}\0\0\0\0{4}\0\0\0{5}", data.Position, data.Country, data.Color, data.Drink, data.Animal, data.Cigarette);
}
else
{
Console.WriteLine("\0{0}\0\0\0\0{1}\0\0{2}\0\0{3}\0\0{4}\0\0\0{5}", data.Position, data.Country, data.Color, data.Drink, data.Animal, data.Cigarette);
}
}
}
Console.Read();

小結
兩種推導的方式思維其實還蠻不一樣的,相對來說人工的需要自己的去按照自己經驗,知識,去做出一些判斷,在一些難點有自己的一套解決思路,比如說條件3丹麥人喝茶在自己推導的時候是一個難點,而在寫程序的時候直接刪除這種可能即可,寫程序的時候我們需要先窮舉出所有可能,就是很長的where語句那塊,這一階段弄明白了,應該都很明了。屬於自己無意中看到的一個題目,屬於編程的小樂趣吧,也可以算是Linq入門的一個小Demo吧~
