锁定老帖子 主题:国王和100个囚犯
精华帖 (0) :: 良好帖 (10) :: 新手帖 (0) :: 隐藏帖 (8)
|
|
---|---|
作者 | 正文 |
发表时间:2010-01-14
langshao 写道 pujia12345 写道 关键是,你如何知道自己是第一个出去的?
难道囚犯们给国王提议: 亲爱的陛下,我问有一个小小的要求,让我第一个出去吧。 因为不能确定计数员是那个,就全乱套。都认为自己是计数员,见到开灯就关,不就乱完了 15分钟商量的时候就可以指定计数员啦 嗯,看来还是没有理解好题目 |
|
返回顶楼 | |
发表时间:2010-01-14
package KingOfPrisoners;
public class State { private static int sumDay;//大家在牢房的日子 private static boolean light;//院子灯的状态 public static int getSumDay() { return sumDay; } public static boolean getLight() { return light; } public static void setLight(boolean light) { State.light = light; } public static void addDay(){ State.sumDay++; } public static void setSumDay(int sumDay) { State.sumDay = sumDay; } } ---------------------------- package KingOfPrisoners; public class Prisoners { private String name;//姓名:15分钟时间商量谁是计数员(谁进院子看到灯是灭的就开亮) private int outTimes;//该人出去过的次数:主要看看是否是首次出去 private int judgementNumber;//该人敢于判定当前已经出去过的人数(重复出去的算一人):主要是计数员使用 public Prisoners(String name){ this.name=name; } public void out(){//出牢房到院子去 State.addDay();//时间过去了一天 if("计数员".equals(name)) { //如果是他们内定的“计数员" if(State.getLight()==false) {//这个“计数员"进院子发现灯是灭的,就开灯,并将进院子的人数+1 State.setLight(true); judgementNumber++; } } else{//进院子的不是“计数员" if(outTimes==0){//如果是首次进院子 if(State.getLight()==true)//发现灯是开着的,就关灯 State.setLight(false); else {outTimes=0;return;}//如果发现灯本来就是开着的,那就说明在你前面有人第一次来过并且中间计数员没有来计数,那你就认为自己这次不算是第一次来把。 } else {//非首次进院子,不做动作 } } outTimes++;//自身出去次数+1 } public boolean gameOver() { //if("计数员".equals(name)) System.out.println(name+" "+outTimes+" "+judgementNumber+" "+State.getSumDay()); if("计数员".equals(name) && judgementNumber==99){ return true; } else return false; } } ------------------------- package KingOfPrisoners; import java.util.*; public class Game { private Prisoners[] p; public Game(){ p=new Prisoners[100]; State.setLight(true); for(int i=0;i<99;i++){ p[i]=new Prisoners("囚犯"+i); } p[99]=new Prisoners("计数员"); } static public void main(String[] str){ Set<Integer> set=new TreeSet<Integer>(); for (int i=0;i<10000;i++){//测试10000次,看看最短 最长需要多少时间,计数员能确认大家都安全自由了 Game game=new Game(); while(true){ int random=(int)(Math.random()*100); game.p[random].out(); if(game.p[random].gameOver()==true) break; } set.add(State.getSumDay()/365); State.setSumDay(0); } System.out.println(set); } } Result [18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39] 按楼主算法 大概范围就在15-40年 |
|
返回顶楼 | |
发表时间:2010-01-14
最后修改:2010-01-14
pujia12345 写道 package KingOfPrisoners;
public class State { private static int sumDay;//大家在牢房的日子 private static boolean light;//院子灯的状态 public static int getSumDay() { return sumDay; } public static boolean getLight() { return light; } public static void setLight(boolean light) { State.light = light; } public static void addDay(){ State.sumDay++; } public static void setSumDay(int sumDay) { State.sumDay = sumDay; } } ---------------------------- package KingOfPrisoners; public class Prisoners { private String name;//姓名:15分钟时间商量谁是计数员(谁进院子看到灯是灭的就开亮) private int outTimes;//该人出去过的次数:主要看看是否是首次出去 private int judgementNumber;//该人敢于判定当前已经出去过的人数(重复出去的算一人):主要是计数员使用 public Prisoners(String name){ this.name=name; } public void out(){//出牢房到院子去 State.addDay();//时间过去了一天 if("计数员".equals(name)) { //如果是他们内定的“计数员" if(State.getLight()==false) {//这个“计数员"进院子发现灯是灭的,就开灯,并将进院子的人数+1 State.setLight(true); judgementNumber++; } } else{//进院子的不是“计数员" if(outTimes==0){//如果是首次进院子 if(State.getLight()==true)//发现灯是开着的,就关灯 State.setLight(false); else {outTimes=0;return;}//如果发现灯本来就是开着的,那就说明在你前面有人第一次来过并且中间计数员没有来计数,那你就认为自己这次不算是第一次来把。 } else {//非首次进院子,不做动作 } } outTimes++;//自身出去次数+1 } public boolean gameOver() { //if("计数员".equals(name)) System.out.println(name+" "+outTimes+" "+judgementNumber+" "+State.getSumDay()); if("计数员".equals(name) && judgementNumber==99){ return true; } else return false; } } ------------------------- package KingOfPrisoners; import java.util.*; public class Game { private Prisoners[] p; public Game(){ p=new Prisoners[100]; State.setLight(true); for(int i=0;i<99;i++){ p[i]=new Prisoners("囚犯"+i); } p[99]=new Prisoners("计数员"); } static public void main(String[] str){ Set<Integer> set=new TreeSet<Integer>(); for (int i=0;i<10000;i++){//测试10000次,看看最短 最长需要多少时间,计数员能确认大家都安全自由了 Game game=new Game(); while(true){ int random=(int)(Math.random()*100); game.p[random].out(); if(game.p[random].gameOver()==true) break; } set.add(State.getSumDay()/365); State.setSumDay(0); } System.out.println(set); } } Result [18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39] 按楼主算法 大概范围就在15-40年 ls的名字起错了吧。。。应该是PrisonersOfKing |
|
返回顶楼 | |
发表时间:2010-01-14
呵呵,语法不好,见谅
|
|
返回顶楼 | |
发表时间:2010-01-14
解题的思路差不多是这样子。。至于大概多少年能出来没仔细研究。。
题目中有说“这所监狱有一个院子,每天会随机(注意是完全随机)打开一间牢房的门”。。这意味着,可以指定被关进去后的第一天有且只有一个人被放出来——那么,就可以约定,找个人就是负责计数的囚犯;另外,由于负责计数的人可以确定、灯的初始状态也不会影响到——比如按照LZ的算法,如果第一天出来的囚犯、也就是负责计数的人,不论是看到灯是亮、是灭,都把它熄灭,然后再按LZ的思路去处理,不会有问题的。。 |
|
返回顶楼 | |
发表时间:2010-01-14
ageha67 写道 解题的思路差不多是这样子。。至于大概多少年能出来没仔细研究。。
题目中有说“这所监狱有一个院子,每天会随机(注意是完全随机)打开一间牢房的门”。。这意味着,可以指定被关进去后的第一天有且只有一个人被放出来——那么,就可以约定,找个人就是负责计数的囚犯;另外,由于负责计数的人可以确定、灯的初始状态也不会影响到——比如按照LZ的算法,如果第一天出来的囚犯、也就是负责计数的人,不论是看到灯是亮、是灭,都把它熄灭,然后再按LZ的思路去处理,不会有问题的。。 题目中提到:“完成封闭,隔绝,囚犯不知道时间”,所以这第一天也是无从判断的。 |
|
返回顶楼 | |
发表时间:2010-01-14
99个人只能开灯,只有一个人可以关灯
|
|
返回顶楼 | |
发表时间:2010-01-14
52356 写道 这个问题我有几点看法:
1、囚犯不知道时间,也就是说他们不知道自己会是第几个人。根据条件,他们更不知道是第几天。 2、囚犯随机的放风。这里可能出现同一囚犯放风多次的情况。 3、那个路灯是他们唯一交流的工具。 4、现在最大的问题是不知道灯的初始状态。 我的办法: 1、指定计数囚犯。100囚犯中指定一个唯一的计数囚犯。 2、规则: (1)所有囚犯除计数囚犯外,当他是第1次放风的时候,如果灯是关着的则设置灯为开,以后再放风,不干涉灯的状态。但第1次放风时,如果灯是开着的,则自己认为自己没放过风。 (2)计数囚犯统计灯开的次数,统计之后将灯关闭。计数到99时,结束。 细节解释:当计数囚犯第1次出门,如果灯是开着的。会有3种情况:1、灯默认是开着的,他是第1个放风的。2、灯是默认开着的,其他囚犯没有去碰开关。3、灯初始是关着的,一放风囚犯将它改为开。 现在问题出现了,由于不知道灯的初始状态,所以在计数囚犯计第1个数时是有误差的,误差为1人。但如果,计数囚犯放风时看到灯是关着的,那就万事大吉了。 这个思路蛮不错的,但是我还有个疑问: 计数员关灯99次的时候,就说明大家都出来过了,如果灯最初是开着的,那么第一个将灯关闭的人肯定是计数员,计数员认为已经有一个人出来过了(其实还没人出来过),当出来到第98个的时候,计数员就已经数到99,认为大家都出来过了,然后大家都被拉出去砍头了。如果计数员考虑到这种情况,打算多数一个到100,当初始灯是关着的时候,他们就永远都出不去了,因为大家都只开一次,永远都到不了100. |
|
返回顶楼 | |
发表时间:2010-01-14
最后修改:2010-01-14
这个题蛮有意思的,发现前面有些同学都走进死胡同了,呵呵。
说下我的思路: 1、在100个囚犯中任意指定一个为计数员,他第一次放风时改变灯的状态,以后每次放风时如果发现灯的状态较上一次改变了,就改变灯的状态,并使计数值累加1,待到计数值累加到99时就可以确保每个囚犯都放风过了。 2、其它的99个囚犯都记住第一次放风时灯的状态,在以后的放风活动中,当第一次发现灯的状态较上一次改变了,就改变灯的状态,且此后的放风活动中再也不改变灯的状态。 |
|
返回顶楼 | |
发表时间:2010-01-14
我的理解是记数员是不是第一个出去的没有关系,灯的初始状态也没有关系。
记数员自己第一次出去发现灯是关的,那么99次就可以了。 如果记数员第一次出去发现灯是开的,那么为了保证万无一失,多记数一次就可以了。 |
|
返回顶楼 | |