论坛首页 Java企业应用论坛

国王与100个囚犯

浏览 24066 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (6)
作者 正文
   发表时间:2010-08-11  
额··这问题还在讨论。这问题有2个条件不明确~~只要2个中明确一个就可以解决。否则我觉得不可能:
1.谁说第一个,貌似很多人都认为关进去后就知道肯定知道自己是不是第一天放出来,但题目中已经给出了,关进去后不知道时间,那怎么知道我是第一天呢??
2.灯本来是开还是关的。因为本来的状态关乎多1次和少一次的问题,而那1次就是关键。
所以在这2个条件都不知道的情况下属不可能解决的。只要知道其中一个,解决办法我想前面都已经给出来了。
0 请登录后投票
   发表时间:2010-08-11   最后修改:2010-08-11
Crusader 写道
phyeas 写道
事实上,我觉得LZ的脑壳有问题,因为此题的先决条件是囚犯不知道时间,是不是第一天只有国王知道,你被关在一个封闭幽暗终日不见阳光的地方,你能知道过了几天吗?


你要这么死脑筋,我也没办法。你可以自己实验下,不看时钟的情况下,能否判断第一天,我反正行,我的生物种催使我绝对不会睡超过24小时
至于第一天后的日子,就根本不用判断了。。。我想你根本还没理解题目的意思



额~LZ的生物钟可真强大~~那你一直不睡觉~~你知道过了多久么?犹如前面那位说的,我晚上11点关进去。
11:59和00:01放出2个人来,他们知道自己谁是第一个??第二个也可能以为自己是第一个。

不知道谁是第一个的情况下,事先商量好哪一个人做为计数员,但在不知道灯的原始状态下也不可能解出来。因为本来是关的,后面出来的人以为前面有人已经关了然后都没关,但计算员以为是有人关了,然后算了一次(实际一次都没有),那就算多一次了。
0 请登录后投票
   发表时间:2010-08-11  
IcedCoffee 写道
哈哈,刚才在网上看到一个很雷人的解法...
如下:

本人认为此题与开灯或关灯并没有切实关系;(因为100个人中永远也不会有能够证明每个人都出来过的人出现,此题最重要的就是知情人和他所拥有的证据,因为他在牢里,开关灯不会出现知情人),

大家应该注意到的是题目中所提到的修理师傅和送饭者(他们对方案带来帮助)

我认为最佳方案是:

每个人第一次出来放风都要拧下一个灯泡,并带回去。(每人只能拿一个,再次出来不再带回)

回去后把灯泡摔破,用碎片划破身体证明出去过。(这是表示自己出去过最有力的证明)

接下来把灯泡的连接处(尾部)交与送饭人,并要求其传递给下一个送饭的人,下一个人再把得到的所有灯泡,交与送饭人。。。继续传递 。。。。 。。传递中。。。。

当拿到100个灯泡尾部的人(就是知情人了,他可以证明所有人出来过)

ps:此人rpg任务做多了...

哈,这个方法不错,前提是送饭的人国王允许他帮那些囚犯~~
0 请登录后投票
   发表时间:2010-08-12   最后修改:2010-08-12
ls估计还没出去自己就挂了
0 请登录后投票
   发表时间:2010-08-17  
我觉得这道题很有意思,楼主给的思路也很有帮助。
其实是不是第一个人不是重点,我想在关进去之前他们需要讨论的是:
1.找出计数员,这人只负责开灯和计数。
2.其他人只能关灯(灯关着的则不做任何事情。),且只能关灯一次。
0 请登录后投票
   发表时间:2010-08-17  
courage207 写道
哈哈,验证了一下,果然是要几十年才能出来,这个算法不好!
package com.util;

import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

public class King_100Prisoner {
	
	private Set set;
	
	// 记数器(由记数员囚犯用来计数囚犯放出去的人数)
	public int count;
	
	// 记数员囚犯编号
	public int counterman; 
	
	// 用来标记1到50编号的囚犯是否被放过风且关过灯
	public long _1_50 = 0;
	
	// 用来标记51到100编号的囚犯是否被放过风且关过灯
	public long _51_100 = 0;
	
	// 标识灯是否亮着
	public boolean isLightOn = false; 
	
	// 标记经过的天数
	public int day = 0;
	
	// 返回放风囚犯记数
	public int getCount(){
		return count;
	}
	
	// 返回经历的天数
	public int getDay(){
		return day;
	}
	
	// 囚犯被放风
	public void releasePrisoner(int prisoner){

		//map=new TreeMap(); 
		// 放出不明生物
		if(prisoner>100 || prisoner<0){
			System.out.println("放出不明生物");
			return;
		}
		// 第一天被放风的做记数员
		if(day==0){
			counterman = prisoner;
		}
String name = (prisoner==counterman)?"记数员":"囚犯"	;
//System.out.print("第"+day+"天: "+ name +prisoner + "放风...");				
		// 如果放风的是记数员
		if(prisoner == counterman){
			// 如果灯是关着的,将其打开,并且放风计数加1
			if(!isLightOn){
				isLightOn = true;
				count++;			
//System.out.print("发现灯是关着的将放风计数+1");				
			}
			
		}else{ // 如果放风的是普通囚犯
			
			// 如果囚犯未被放过风且关过灯
			if((prisoner&_1_50)==0 && (prisoner&_51_100)==0){
				
				// 第一次放风遇见灯时开着时,关灯,记录该囚犯放过风且关过灯
				set.add(prisoner);
				if(isLightOn==true){
					isLightOn = false;
					
					if(prisoner<=50){
						_1_50 = _1_50 &prisoner;//| (0x1L<<(prisoner-1));
					}else{
						_51_100 = _51_100 &prisoner;//| (0x1L<<(prisoner-1));
					}
//System.out.println(prinsone"第一次遇见灯开着,于是将灯关了,并且记住从此放风什么也不干了");					
				}else{
//System.out.println("发现灯是关着的,什么也没干");				
				}
			}else{
//System.out.println("已经放过风,关过灯,于是什么也没干");
			}
		}
		day++;	
	}
	
	public static void main(String[] args) {
		King_100Prisoner demo = new King_100Prisoner();
		Random r = new Random(new Date().getTime());
		demo.set=new TreeSet();
		int prisoner = 0;
		while(demo.getCount()<100){
			prisoner = r.nextInt(100)+1;
			demo.releasePrisoner(prisoner);
		}
		System.out.println("共经历了"+demo.day+"天后,所有囚犯"+demo.counterman+"获释!");
		Iterator iter=demo.set.iterator();
		while(iter.hasNext()){
			System.out.println(iter.next());
		}
	}

}

 

我用的是你方法,成功了。楼主的算法有点问题就是这段

                                        if(prisoner<=50){
						_1_50 = _1_50 &prisoner;//| (0x1L<<(prisoner-1));
					}else{
						_51_100 = _51_100 &prisoner;//| (0x1L<<(prisoner-1));
					}
0 请登录后投票
   发表时间:2010-08-17  
楼上的你改的什么,我没看懂?
我原来代码的意思是用两个long总共128位,用第一个long的前50位标记前50个囚犯的关灯状态,第二个long的前50位标记后50个囚犯的关灯状态。。。
你改的则使if((prisoner&_1_50)==0 && (prisoner&_51_100)==0)永远为真了...
0 请登录后投票
   发表时间:2010-08-21  
很好有意思的题目哦
0 请登录后投票
   发表时间:2011-03-03  
Crusader 写道
哎,我发现很多人都喜欢砖牛角。。。

第一天的判断,请把题目中的囚犯也想成是真实的人,他们不是猪。。

至于为什么要第一个人来记数?当然也可以不,如果不指定第一个人的话(但必须在事前指定一个固定的囚犯),第一天的判断也可以取消,但是囚犯坐牢的天数将增加

我倒是觉得 ~ 如果他们不是猪的话~ 还那么有秩序~ 他们完全可以联合起来越狱~
根本不用跟国王玩什么游戏.
0 请登录后投票
   发表时间:2011-03-04  
IcedCoffee 写道
哈哈,刚才在网上看到一个很雷人的解法...
如下:

本人认为此题与开灯或关灯并没有切实关系;(因为100个人中永远也不会有能够证明每个人都出来过的人出现,此题最重要的就是知情人和他所拥有的证据,因为他在牢里,开关灯不会出现知情人),

大家应该注意到的是题目中所提到的修理师傅和送饭者(他们对方案带来帮助)

我认为最佳方案是:

每个人第一次出来放风都要拧下一个灯泡,并带回去。(每人只能拿一个,再次出来不再带回)

回去后把灯泡摔破,用碎片划破身体证明出去过。(这是表示自己出去过最有力的证明)

接下来把灯泡的连接处(尾部)交与送饭人,并要求其传递给下一个送饭的人,下一个人再把得到的所有灯泡,交与送饭人。。。继续传递 。。。。 。。传递中。。。。

当拿到100个灯泡尾部的人(就是知情人了,他可以证明所有人出来过)

ps:此人rpg任务做多了...

看了之前大家都跟着楼主的思路走,,,你这个让人眼前一亮
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics