LINQ解 爱因斯坦迷题

文/foundation  出处/博客园

据说是爱因斯坦迷题,不知是真是假,不过这道集合运算的题还是挺有意思的,比一般的[谁是凶手]的题多了集合项之间的关系
用linq的集合运算符,不用if、for等控制流语句解一下这道题.

本题的解题方式用的是工作流处理问题的方式
将事项分为阶段(也叫状态),每个阶段按一定顺连接,每个阶段内由处理该阶段问题的一组业务结点组成,业务结点的添加或移除不影响处理问题的架构
还有,业务结点最好是真正真实业务的映射,最好不要出现
[ 8、挪威人住第一间房 ]+  [14、挪威人住蓝色房子隔壁],推出[第2间房子是蓝色]的业务结点,要推也得由系统推(这叫反映链),而不能由开发人员推,这样就可以在架构完成后随意修改业务结点,本例用的就是这种方式,由于没有人工推理加入,执行效率有些低,
在Core2 Duo CPU 7300上,用 System.Diagnostics.Stopwatch
Debug  模式下用时:06.5122712
Release 模式下用时:05.2872722



问题:
在一条街上,有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香烟的人有一个喝水的邻居


代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            //--------------------------1阶段----------------------------------------------
            int[] 房子位置 = new int[] { 1, 2, 3, 4, 5 };
            string[] 房子颜色 = new string[] { "黄", "蓝", "红", "绿", "白" };
            string[] 国籍 = new string[] { "挪威", "丹麦", "英国", "德国", "瑞典" };
            string[] 宠物 = new string[] { "猫", "马", "鸟", "鱼", "狗" };
            string[] 饮品 = new string[] { "水", "茶", "牛奶", "咖啡", "啤酒" };
            string[] 香烟 = new string[] { "Dunhill", "Blends", "Pall Mall", "Prince", "Blue Master" };

            var v = (from t1 in 房子位置
                    from t2 in 房子颜色
                    from t3 in 国籍
                    from t4 in 宠物
                    from t5 in 饮品
                    from t6 in 香烟
                    select new a { 房子位置 = t1, 房子颜色 = t2, 国籍 = t3, 宠物 = t4, 饮品 = t5, 香烟 = t6 }).ToList();

            //------------------------2阶段-------------------------------------------------
            //1、英国人住红色房子
            v.RemoveAll(p => p.国籍 == "英国" && p.房子颜色 != "红");
            v.RemoveAll(p => p.国籍 != "英国" && p.房子颜色 == "红");

            //2、瑞典人养狗
            v.RemoveAll(p => p.国籍 == "瑞典" && p.宠物 != "狗");
            v.RemoveAll(p => p.国籍 != "瑞典" && p.宠物 == "狗");

            //3、丹麦人喝茶
            v.RemoveAll(p => p.国籍 == "丹麦" && p.饮品 != "茶");
            v.RemoveAll(p => p.国籍 != "丹麦" && p.饮品 == "茶");

            //5、绿色房子主人喝咖啡
            v.RemoveAll(p => p.房子颜色 == "绿" && p.饮品 != "咖啡");
            v.RemoveAll(p => p.房子颜色 != "绿" && p.饮品 == "咖啡");

            //6、抽Pall Mall 香烟的人养鸟
            v.RemoveAll(p => p.香烟 == "Pall Mall" && p.宠物 != "鸟");
            v.RemoveAll(p => p.香烟 != "Pall Mall" && p.宠物 == "鸟");

            //7、黄色房子主人抽Dunhill 香烟
            v.RemoveAll(p => p.房子颜色 == "黄" && p.香烟 != "Dunhill");
            v.RemoveAll(p => p.房子颜色 != "黄" && p.香烟 == "Dunhill");

            //8、挪威人住第一间房
            v.RemoveAll(p => p.国籍 == "挪威" && p.房子位置 != 1);
            v.RemoveAll(p => p.国籍 != "挪威" && p.房子位置 == 1);

            //9、住在中间房子的人喝牛奶
            v.RemoveAll(p => p.房子位置 == 3 && p.饮品 != "牛奶");
            v.RemoveAll(p => p.房子位置 != 3 && p.饮品 == "牛奶");

            //12、抽Blue Master的人喝啤酒
            v.RemoveAll(p => p.香烟 == "Blue Master" && p.饮品 != "啤酒");
            v.RemoveAll(p => p.香烟 != "Blue Master" && p.饮品 == "啤酒");

            //13、德国人抽Prince香烟
            v.RemoveAll(p => p.国籍 == "德国" && p.香烟 != "Prince");
            v.RemoveAll(p => p.国籍 != "德国" && p.香烟 == "Prince");

            //-------------------------3阶段------------------------------------------------
            //喷不同颜色,住不同国籍的人,喝不同的饮料,抽不同品牌的香烟,养不同的宠物
            var vv = (from g1 in v.Where(p => p.房子位置 == 1)
                    from g2 in v.Where(p => p.房子位置 == 2)
                    from g3 in v.Where(p => p.房子位置 == 3)
                    from g4 in v.Where(p => p.房子位置 == 4)
                    from g5 in v.Where(p => p.房子位置 == 5)
                    where g1.饮品 != g2.饮品 && g1.饮品 != g3.饮品 && g1.饮品 != g4.饮品 && g1.饮品 != g5.饮品 &&
                            g2.饮品 != g3.饮品 && g2.饮品 != g4.饮品 && g2.饮品 != g5.饮品 &&
                            g3.饮品 != g4.饮品 && g3.饮品 != g5.饮品 &&
                            g4.饮品 != g5.饮品 &&
                            g1.宠物 != g2.宠物 && g1.宠物 != g3.宠物 && g1.宠物 != g4.宠物 && g1.宠物 != g5.宠物 &&
                            g2.宠物 != g3.宠物 && g2.宠物 != g4.宠物 && g2.宠物 != g5.宠物 &&
                            g3.宠物 != g4.宠物 && g3.宠物 != g5.宠物 &&
                            g4.宠物 != g5.宠物 &&
                            g1.国籍 != g2.国籍 && g1.国籍 != g3.国籍 && g1.国籍 != g4.国籍 && g1.国籍 != g5.国籍 &&
                            g2.国籍 != g3.国籍 && g2.国籍 != g4.国籍 && g2.国籍 != g5.国籍 &&
                            g3.国籍 != g4.国籍 && g3.国籍 != g5.国籍 &&
                            g4.国籍 != g5.国籍 &&
                            g1.香烟 != g2.香烟 && g1.香烟 != g3.香烟 && g1.香烟 != g4.香烟 && g1.香烟 != g5.香烟 &&
                            g2.香烟 != g3.香烟 && g2.香烟 != g4.香烟 && g2.香烟 != g5.香烟 &&
                            g3.香烟 != g4.香烟 && g3.香烟 != g5.香烟 &&
                            g4.香烟 != g5.香烟 &&
                            g1.房子颜色 != g2.房子颜色 && g1.房子颜色 != g3.房子颜色 && g1.房子颜色 != g4.房子颜色 && g1.房子颜色 != g5.房子颜色 &&
                            g2.房子颜色 != g3.房子颜色 && g2.房子颜色 != g4.房子颜色 && g2.房子颜色 != g5.房子颜色 &&
                            g3.房子颜色 != g4.房子颜色 && g3.房子颜色 != g5.房子颜色 &&
                            g4.房子颜色 != g5.房子颜色 &&
                            g1.房子位置 != g2.房子位置 && g1.房子位置 != g3.房子位置 && g1.房子位置 != g4.房子位置 && g1.房子位置 != g5.房子位置 &&
                            g2.房子位置 != g3.房子位置 && g2.房子位置 != g4.房子位置 && g2.房子位置 != g5.房子位置 &&
                            g3.房子位置 != g4.房子位置 && g3.房子位置 != g5.房子位置 &&
                            g4.房子位置 != g5.房子位置
                      select new List<a> { g1, g2, g3, g4, g5 }).ToList();

            //------------------------4阶段-------------------------------------------------

            // 4、绿色房子在白色房子左面
            //(绿房子.房子位置房子 - 白.房子位置) == -1 表示左面
            vv.RemoveAll(pp => -1 != pp.Single(p => p.房子颜色 == "绿").房子位置 - pp.Single(p => p.房子颜色 == "白").房子位置);


            //10、抽Blends香烟的人住在养猫的人隔壁
            // Abc(Blends香烟的人.房子位置 - 养猫.房子位置) == 1 表示是隔壁
            vv.RemoveAll(pp => 1 != System.Math.Abs(pp.Single(p => p.宠物 == "猫").房子位置 - pp.Single(p => p.香烟 == "Blends").房子位置));


          //11、养马的人住抽Dunhill 香烟的人隔壁
            vv.RemoveAll(pp => 1 != System.Math.Abs(pp.Single(p => p.宠物 == "马").房子位置 - pp.Single(p => p.香烟 == "Dunhill").房子位置));


            //14、挪威人住蓝色房子隔壁
            vv.RemoveAll(pp => 1 != System.Math.Abs(pp.Single(p => p.国籍 == "挪威").房子位置 - pp.Single(p => p.房子颜色 == "蓝").房子位置));

            //15、抽Blends香烟的人有一个喝水的邻居
            vv.RemoveAll(pp => 1 != System.Math.Abs(pp.Single(p => p.香烟 == "Blends").房子位置 - pp.Single(p => p.饮品 == "水").房子位置));

            //--------------------------5阶段-----------------------------------------------

            //问题是:谁养鱼?
            var who= vv.Select(pp => pp.Single(p => p.宠物 == "鱼"));

            who.ToList().ForEach(p => System.Console.WriteLine("养鱼:{0}",p));

            System.Console.WriteLine("结构:");
         
            vv.ForEach(p=>p.ForEach(pp=>System.Console.WriteLine(pp)));

            //------------------------------------------------------------------------
            System.Console.Read();
        }
    }

    class a
    {
        public int 房子位置;

        public string 房子颜色;

        public string 国籍;

        public string 宠物;

        public string 饮品;

        public string 香烟;

        public override string ToString()
        {

            return string.Format("{0},{1},{2},{3},{4},{5}", 房子位置, 房子颜色, 国籍, 宠物, 饮品, 香烟);
        }

    }
}

结果

 附件: 您所在的用户组无法下载或查看附件

 感谢原创者的辛勤劳动,希望对您有所帮助,转载请注明原出处。
 您可能对 [Linq] 的这些文章也感兴趣:

LINQ to SQL活学活用(3):嗅出“臭味”烟消云散
分手后的情书
LINQ体验(17)——LINQ to SQL语句之动态查询
Linq系列:基础与本质(Part III)
LINQ -对付SQL Injection的"免费补洞策略"
使用LINQ轻松防御SQL注入攻击
使用linq to xml 快速创建RSS
LINQ体验(10)——LINQ语句之开放式并发控制和事务
LINQ to SQL的开发会停止吗?
LINQ to SQL活学活用(4):监视你的一举一动