论坛首页 Java企业应用论坛

国王和100个囚犯

浏览 36074 次
精华帖 (0) :: 良好帖 (10) :: 新手帖 (0) :: 隐藏帖 (8)
作者 正文
   发表时间:2010-01-14  
langshao 写道
pujia12345 写道
关键是,你如何知道自己是第一个出去的?
难道囚犯们给国王提议:
亲爱的陛下,我问有一个小小的要求,让我第一个出去吧。

因为不能确定计数员是那个,就全乱套。都认为自己是计数员,见到开灯就关,不就乱完了


15分钟商量的时候就可以指定计数员啦

嗯,看来还是没有理解好题目
0 请登录后投票
   发表时间: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年
0 请登录后投票
   发表时间: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
0 请登录后投票
   发表时间:2010-01-14  
呵呵,语法不好,见谅
0 请登录后投票
   发表时间:2010-01-14  
解题的思路差不多是这样子。。至于大概多少年能出来没仔细研究。。
题目中有说“这所监狱有一个院子,每天会随机(注意是完全随机)打开一间牢房的门”。。这意味着,可以指定被关进去后的第一天有且只有一个人被放出来——那么,就可以约定,找个人就是负责计数的囚犯;另外,由于负责计数的人可以确定、灯的初始状态也不会影响到——比如按照LZ的算法,如果第一天出来的囚犯、也就是负责计数的人,不论是看到灯是亮、是灭,都把它熄灭,然后再按LZ的思路去处理,不会有问题的。。
0 请登录后投票
   发表时间:2010-01-14  
ageha67 写道
解题的思路差不多是这样子。。至于大概多少年能出来没仔细研究。。
题目中有说“这所监狱有一个院子,每天会随机(注意是完全随机)打开一间牢房的门”。。这意味着,可以指定被关进去后的第一天有且只有一个人被放出来——那么,就可以约定,找个人就是负责计数的囚犯;另外,由于负责计数的人可以确定、灯的初始状态也不会影响到——比如按照LZ的算法,如果第一天出来的囚犯、也就是负责计数的人,不论是看到灯是亮、是灭,都把它熄灭,然后再按LZ的思路去处理,不会有问题的。。

题目中提到:“完成封闭,隔绝,囚犯不知道时间”,所以这第一天也是无从判断的。
0 请登录后投票
   发表时间:2010-01-14  
99个人只能开灯,只有一个人可以关灯
0 请登录后投票
   发表时间: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.
2 请登录后投票
   发表时间:2010-01-14   最后修改:2010-01-14
这个题蛮有意思的,发现前面有些同学都走进死胡同了,呵呵。
说下我的思路:
1、在100个囚犯中任意指定一个为计数员,他第一次放风时改变灯的状态,以后每次放风时如果发现灯的状态较上一次改变了,就改变灯的状态,并使计数值累加1,待到计数值累加到99时就可以确保每个囚犯都放风过了。
2、其它的99个囚犯都记住第一次放风时灯的状态,在以后的放风活动中,当第一次发现灯的状态较上一次改变了,就改变灯的状态,且此后的放风活动中再也不改变灯的状态。
1 请登录后投票
   发表时间:2010-01-14  
我的理解是记数员是不是第一个出去的没有关系,灯的初始状态也没有关系。
记数员自己第一次出去发现灯是关的,那么99次就可以了。
如果记数员第一次出去发现灯是开的,那么为了保证万无一失,多记数一次就可以了。
0 请登录后投票
论坛首页 Java企业应用版

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