欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

《爱因斯坦的问题》解答 Myeclipse算法J# 

程序员文章站 2022-06-04 16:03:48
...

看到这样一个问题,题目就叫《爱因斯坦的问题》,光看题目就很有意思,打开后看了问题内容,第一反应是“晕”,而后在纸上画了画,大体理清了思路,不过实在是懒得算,就准备写个程序来帮忙。

首先把问题的内容贴出来:

爱因斯坦的超级问题
1、在一条街上,有5座房子,喷了5种颜色。
2、每个房里住着不同国籍的人
3、每个人喝不同的饮料,抽不同品牌的香烟,养不同的宠物
问题是:谁养鱼?
提示:
1、英国人住红色房子
2、瑞典人养狗
3、丹麦人喝茶
4、绿色房子在白色房子左面
5、绿色房子主人喝咖啡
6、抽PallMall香烟的人养鸟
7、黄色房子主人抽Dunhill香烟
8、住在中间房子的人喝牛奶
9、挪威人住第一间房
10、抽Blends香烟的人住在养猫的人隔壁
11、养马的人住抽Dunhill香烟的人隔壁
12、抽BlueMaster的人喝啤酒
13、德国人抽Prince香烟
14、挪威人住蓝色房子隔壁
15、抽Blends香烟的人有一个喝水的邻居

 通过程序解这种题,第一个反应是穷举法。现在先算算穷举法有多少种组合。一条街,包含5间有序的房屋,每间房屋有五个互不相同的属性:国籍、颜色、宠物、饮料和香烟。因为5间房屋相同类型的属性都不一样,所以每个属性都有5!=120种组合,5种属性加起来,共有120^5=24883200000种!接近250亿了。

直接穷举这么多种情况,显得很不合适,所以在使用穷举法的时候,不要等把一种组合确定下来之后再去判断是否符合条件,而是在组合中的一部分属性确定下来后马上做判断,这样会快很多。

本来想把房屋和街道抽象成java类,但是感觉有点兴师动众,所以就只写了一个类,以解决问题为主。下面直接上代码。

import java.util.ArrayList;

public class Einstein {
	private static final String[] MEN = { "挪威", "瑞典", "英国", "丹麦", "德国" };
	private static final int NORWAY = 0;
	private static final int SWEDEN = 1;
	private static final int ENGLAND = 2;
	private static final int DENMARK = 3;
	private static final int GERMANY = 4;
	// ================================================================
	private static final String[] PET = { "狗", "鸟", "马", "猫", "鱼" };
	private static final int DOG = 0;
	private static final int BIRD = 1;
	private static final int HORSE = 2;
	private static final int CAT = 3;
	private static final int FISH = 4;
	// ================================================================
	private static final String[] COL = { "蓝色", "红色", "黄色", "白色", "绿色" };
	private static final int BLUE = 0;
	private static final int RED = 1;
	private static final int YELLOW = 2;
	private static final int WHITE = 3;
	private static final int GREEN = 4;
	// ================================================================
	private static final String[] WIN = { "牛奶", "咖啡", "啤酒", "水", "茶" };
	private static final int MILK = 0;
	private static final int COFFE = 1;
	private static final int BEER = 2;
	private static final int WHAT = 3;
	private static final int TEE = 4;

	// ================================================================
	private static final String[] SMO = { "PallMall", "Dunhill", "BlueMaster",
			"Prince", "Blends" };
	private static final int PM = 0;
	private static final int DH = 1;
	private static final int BM = 2;
	private static final int P = 3;
	private static final int B = 4;

	// ================================================================
	private static final ArrayList<int[]> list = new ArrayList<int[]>(120);

	public static void main(String[] args) {
		// 先生成0-4的全排列。算法很笨,但是很有效。
		for (int i1 = 0; i1 < 5; i1++) {
			for (int i2 = 0; i2 < 5; i2++) {
				if (i2 == i1) {
					continue;
				}
				for (int i3 = 0; i3 < 5; i3++) {
					if (i3 == i1 || i2 == i1 || i2 == i3) {
						continue;
					}
					for (int i4 = 0; i4 < 5; i4++) {
						if (i3 == i1 || i2 == i1 || i4 == i1 || i3 == i4
								|| i3 == i2 || i2 == i4) {
							continue;
						}
						int[] arr = new int[] { i1, i2, i3, i4,
								(10 - i1 - i2 - i3 - i4) };
						list.add(arr);
					}
				}
			}
		}
		getM();
	}

	/**
	 * 国籍的全排列
	 */
	private static final void getM() {
		long begin = System.nanoTime();
		// 开始
		for (int[] men : list) {
			if (men[0] != NORWAY) {
				// 9、挪威人住第一间房
				continue;
			}
			getC(men);
		}
		System.out.println("耗时:" + (System.nanoTime() - begin) + "纳秒。");
	}

	/**
	 * 颜色的全排列
	 */
	private static void getC(int[] men) {
		out: for (int[] color : list) {
			if (color[1] != BLUE || color[4] == GREEN) {
				// 14、挪威人住蓝色房子隔壁
				// 所以,左起第二间房屋一定是蓝色色的
				// 4、绿色房子在白色房子左面
				// 所以,最右边的房屋一定不是绿色的
				continue;
			}
			for (int i = 0; i < 4; i++) {
				if (color[i] == GREEN && color[i + 1] != WHITE) {
					// 4、绿色房子在白色房子左面
					continue out;
				}
			}
			for (int i = 0; i < 5; i++) {
				if (men[i] == ENGLAND && color[i] != RED) {
					// 1、英国人住红色房子
					continue out;
				}
			}
			getP(men, color);
		}
	}

	/**
	 * 宠物的全排列
	 */
	private static void getP(int[] men, int[] color) {
		out: for (int[] pet : list) {
			for (int i = 0; i < 5; i++) {
				if (men[i] == SWEDEN && pet[i] != DOG) {
					// 2、瑞典人养狗
					continue out;
				}
			}
			getW(men, color, pet);
		}
	}

	/**
	 * 饮料的全排列
	 */
	private static void getW(int[] men, int[] color, int[] pet) {
		out: for (int[] win : list) {
			if (win[2] != MILK) {
				// 8、住在中间房子的人喝牛奶
				continue;
			}
			for (int i = 0; i < 5; i++) {
				if (men[i] == DENMARK && win[i] != TEE) {
					// /3、丹麦人喝茶
					continue out;
				}
			}
			for (int i = 0; i < 5; i++) {
				if (color[i] == GREEN && win[i] != COFFE) {
					// 5、绿色房子主人喝咖啡
					continue out;
				}
			}
			getS(men, color, pet, win);
		}
	}

	/**
	 * 香烟的全排列
	 */
	private static void getS(int[] men, int[] color, int[] pet, int[] win) {
		out: for (int[] smo : list) {
			for (int i = 0; i < 5; i++) {
				if (pet[i] == BIRD && smo[i] != PM) {
					// 6、抽PallMall香烟的人养鸟
					continue out;
				}
			}
			for (int i = 0; i < 5; i++) {
				if (color[i] == YELLOW && smo[i] != DH) {
					// 7、黄色房子主人抽Dunhill香烟
					continue out;
				}
			}
			for (int i = 0; i < 5; i++) {
				if (win[i] == BEER && smo[i] != BM) {
					// /12、抽BlueMaster的人喝啤酒
					continue out;
				}
			}
			for (int i = 0; i < 5; i++) {
				int man = men[i];
				if (man == GERMANY && smo[i] != P) {
					// 13、德国人抽Prince香烟
					continue out;
				}
			}

			boolean b = true;
			for (int i = 0; i < 4; i++) {
				if ((smo[i] == B && pet[i + 1] == CAT)
						|| (smo[i + 1] == B && pet[i] == CAT)) {
					// 10、抽Blends香烟的人住在养猫的人隔壁
					b = false;
					break;
				}
			}
			if (b) {
				continue;
			}

			b = true;
			for (int i = 0; i < 4; i++) {
				if ((smo[i] == B && win[i + 1] == WHAT)
						|| (smo[i + 1] == B && win[i] == WHAT)) {
					// 15、抽Blends香烟的人有一个喝水的邻居
					b = false;
					break;
				}
			}
			if (b) {
				continue;
			}

			b = true;
			for (int i = 0; i < 4; i++) {
				if ((smo[i] == DH && pet[i + 1] == HORSE)
						|| (smo[i + 1] == DH && pet[i] == HORSE)) {
					// 11、养马的人住抽Dunhill香烟的人隔壁
					b = false;
					break;
				}
			}
			if (b) {
				continue;
			}
			int[][] old = new int[][] { men, color, pet, win, smo };
			print(old);
		}
	}

	/**
	 * 打印结果
	 */
	private static final void print(int[][] old) {
		int[][] arr = new int[5][5];
		// 转置
		for (int i = 0; i < 5; i++) {
			for (int j = 0; j < 5; j++) {
				arr[j][i] = old[i][j];
			}
		}
		StringBuilder sb = new StringBuilder("房屋位置\t国籍\t房子颜色\t宠物\t饮料\t香烟");
		for (int i = 0; i < arr.length; i++) {
			sb.append("\n左起").append(i + 1);
			sb.append("\t").append(MEN[arr[i][0]]);
			sb.append("\t").append(COL[arr[i][1]]);
			sb.append("\t").append(PET[arr[i][2]]);
			sb.append("\t").append(WIN[arr[i][3]]);
			sb.append("\t").append(SMO[arr[i][4]]);
		}
		sb.append("\n============================");
		System.out.println(sb);
	}
}

 在MyEclipse中的运行结果:


《爱因斯坦的问题》解答
            
    
    
        Myeclipse算法J# 
 
《爱因斯坦的问题》解答
            
    
    
        Myeclipse算法J# 

  • 《爱因斯坦的问题》解答
            
    
    
        Myeclipse算法J# 
  • 大小: 13 KB