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

告诉你什么是优雅的代码(4)-----智力题的解法(答案)

程序员文章站 2022-05-17 19:39:54
...
以下智力题摘自某一帖子。在纸上画了一下之后有了答案。出于职业敏感,开始考虑如何用程序来解决。现在已经有了基本的模型和算法,就等实现。不过,这次不再急于告诉大家什么是优雅的代码,让聪明的你们先来思考一下。实现随后放出。如果帖子过快被隐藏,那么你们又错失一次学习优雅代码的机会了。好了,废话少说,大家一起动脑思考吧。


   1. 6.宴会桌旁  
   2.   
   3.   在某宾馆的宴会厅里,有4位朋友正围桌而坐,侃侃而谈。他们用了中、英、法、日4种语言。现已知:  
   4.   
   5.   A.甲、乙、丙各会两种语言,丁只会一种语言;  
   6.   
   7.   B.有一种语言4人中有3人都会;  
   8.   
   9.   C.甲会日语,丁不会日语,乙不会英语;  
  10.   
  11.   D. 甲与丙、丙与丁不能直接交谈,乙与丙可以直接交谈;  
  12.   
  13.   E. 没有人既会日语,又会法语。  
  14.   
  15.   请问:甲乙丙丁各会什么语言?  



首先,建立一张二维表,如图所示:
*     中  英 法 日
*  甲          
*  乙    
*  丙
*  丁          
某人掌握某语言则标1,不掌握则标0。则问题转化为在表的状态空间下找出符合题中约束的一张表。状态空间的数目为 16*16*16*16,这个数虽然不是天文数字,但效率显然是低下的,编程起来也异常麻烦。
不要急,我们来整理下题中纷乱的约束,重新整理如下:

  甲: 会日语,会两种语言,不会法语
  乙: 不会英语,会两种语言,不同时会日语和法语
  丙: 会两种语言,不同时会日语和法语
  丁: 不会日语,只会一种语言

  全局约束:甲与丙、丙与丁不能直接交谈,乙与丙可以直接交谈,有一种语言4人中有3人都会

Ok,现在二维表的状态如下:
       中  英  法  日
   甲                1
   乙     0
   丙
   丁                0
先忽略全局约束,根据各人的约束,则状态空间变为(其中c(a,b)是组合数):
(c(3,1) - 1) * (c(3,2) - 1) * (c(4,2)-1)*c(3,1) = 2*2*5*3 = 60
显然非常少了。接下来我们只要在这个状态空间下寻找出满足全局约束的状态就可以了。

就在我准备用二维数组来实现的时候,一个火花在脑中突然迸发。那就是按位与运算。我们来看下与运算:

1001&1100 = 1000  0010&0101 = 0000

看出端倪了吗?两个人如果能互相交流证明其状态按位与的结果不为0,否则则为0.

于是一个优雅的方案浮出水面:

/*
 *   A.甲、乙、丙各会两种语言,丁只会一种语言;  
#   
#   B.有一种语言4人中有3人都会;  
#   
#   C.甲会日语,丁不会日语,乙不会英语;  
#   
#   D. 甲与丙、丙与丁不能直接交谈,乙与丙可以直接交谈;  
#   
#   E. 没有人既会日语,又会法语。  
 
 *
 *分析
 *  甲: 会日语,会两种语言,不会法语
 *  乙: 不会英语,会两种语言,不同时会日语和法语
 *  丙: 会两种语言,不同时会日语和法语
 *  丁: 不会日语,只会一种语言
 *  全局约束:甲与丙、丙与丁不能直接交谈,乙与丙可以直接交谈,有一种语言4人中有3人都会
 *  
 *     8   4 2  1
 *     中  英 法 日 
 *  甲           1
 *  乙     0
 *  丙
 *  丁           0
 */
public class Fun {
	public static void main(String[] args) {
		
		int[] a = {9,5};
		int[] b = {10,9};
		int[] c = {5,6,9,10,12};
		int[] d = {8,4,2};
		boolean solved = false;
		
		for (int i = 0; i < a.length&&!solved; i++) {
			
			
			for (int j = 0; j < b.length&&!solved; j++) {
				
				
				for (int k = 0; k < c.length&&!solved; k++) {
					//甲与丙不能直接交谈
					if((a[i]&c[k]) != 0 )
						continue;
					//乙与丙可以直接交谈
					if((b[j]&c[k]) == 0)
						continue;
					
					for (int l = 0; l < d.length; l++) {
						//丙与丁不能直接交谈
						if((c[k]&d[l]) != 0)
							continue;
						//有一种语言4人中有3人都会
						if((a[i]&b[j]&c[k])!=0 || (a[i]&b[j]&d[l])!=0 || (a[i]&c[k]&d[l])!=0
						|| (b[j]&c[k]&d[l])!=0 ){
							
							System.out.print("甲:");
							parse(a[i]);
							System.out.println();
							System.out.print("乙:");
							parse(b[j]);
							System.out.println();
							System.out.print("丙:");
							parse(c[k]);
							System.out.println();
							System.out.print("丁:");
							parse(d[l]);
							System.out.println();
							solved = true;
							break;
						}
					}
				}
			}
		}
		
	}

	private static void parse(int num) {
		while(num!=0){
			if(num >= 8){
				System.out.print(" 中 ");
				num -= 8;
			}
			else if(num >= 4){
				System.out.print(" 英 ");
				num -= 4;
			}
			else if(num >= 2){
				System.out.print(" 法 ");
				num -= 2;
			}
			else{
				System.out.print(" 日 ");
				num -= 1;
			}
		}
		
	}
}