病狗问题 -- 假设法求解

 

题目:

    村子中有50个人,每人有一条狗。在这50条狗中有病狗(这种病不会传染)。于是人们就要找出病狗。

    每个人可以观察其他的49条狗,以判断它们是否生病(如果有病一定能看出来),只是自己的狗不能看。
 观察后得到的结果不得交流,也不能通知病狗的主人,一天只能看一次。主人一旦推算出自己家的是病狗就要枪毙自己的狗(发现后必须在一天内枪毙),
    而且每个人只有权利枪毙自己的狗,没有权利打死其他人的狗。

    第一天大家全看完了,但枪没有响,第二天仍没有枪响。到了第三天传来一阵枪声,
   问村里共有几条病狗,如何推算得出?

 

 

=======================================

 1. 思考: 第一时间还没有想到直接求解的办法。先采用假设法,简化处理。呵呵。。
 假设有1只狗,第几天会有枪声。
 假设有2只狗,第几天会有枪声。
 。。。

 2. 解法: 按照这个思路。将信息抽象为两个类。村庄和拥有狗的村民。
  村民
      拥有一支狗,且狗的状态不可变。
      有查看别人家狗的动作。
      有kill自己狗的动作。
      另外,还需要提供一个,供别人查看自己的狗状态的动作。

  村庄(简化为村庄的村长来组织/发起动作。。村庄与村长奇妙的合体了。。。。哈哈、、)
      村庄有村民入住动作。
      村长组织村民 看狗。。。
      村长给村民一段时间,用来杀自己家狗。

 3. 总结:
  如果按照这个解法来看,能够用到的技术主要是并发计算了。
  1). 在每个人和每个人的动作互相独立,没有关联,可以完全解耦。可以并行。
  2). 每个人在观察完所有狗(除了自己)之后就有了判断,可以决定杀还是不杀了。
  3). 每天的事件也可以做到并行处理。但是会出现过度计算的问题。需要增加中断和撤销机制。

  第一时间没有想到更好的解决方案。哎。思维短板啊。。。。。

 

 

附code:

 

import java.util.List;

/**
 * Created by zkai on 2015/1/21.
 */
public class PetOwner {
    private final boolean isSickDog;
    private boolean consideredOwnerSickDog;

    public PetOwner(boolean isSickDog) {
        this.isSickDog = isSickDog;
    }

    /**
     * @param day 第几天
     * @return 看到病狗的数量
     */
    public boolean watchOtherDogAndThink(int day, List<PetOwner> petOwners) {
        int count = 0;
        for (PetOwner petOwner : petOwners) {
            if (petOwner != this && petOwner.dogStatus(this)) {
                count++;
            }
        }
        // 此处是最关键的。day 与 count 的关系。
        consideredOwnerSickDog = day - count == 1; // 看到病狗的数量,和日期的关系。
        return consideredOwnerSickDog;
    }

    /**
     *
     * @return 是否枪杀了自己的狗。true:杀了,false:没杀
     */
    public boolean killMyselfDog() {
        if (consideredOwnerSickDog) {
            System.out.println("▄︻┳═一   枪杀自己的狗~~~ 嘭~~~");
        }
        return consideredOwnerSickDog;
    }

    /**
     * 查看狗的状态,必须是非自己
     * @param watcher
     * @return
     */
    public boolean dogStatus(PetOwner watcher) {
        if (watcher == null || watcher == this) {
            throw new IllegalStateException("自己不能看自己的狗");
        }
        return isSickDog;
    }
}

 

 

 

 

 

 

package com.wyfbilling.common.logger.contract;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 
 *
 *
 * Created by zkai on 2015/1/21.
 */
public class Village {
    private final List<PetOwner> petOwners;

    /**
     *
     * @param petOwnerCount 村民数量
     * @param sickDogCount 病狗的数量
     */
    public Village(int petOwnerCount,int sickDogCount) {
        petOwners = Collections.unmodifiableList(init(petOwnerCount, sickDogCount));
    }

    /**
     * 村民入住
     * @param petOwnerCount 村民数量
     * @param sickDogCount 病狗的数量
     */
    private List<PetOwner> init(int petOwnerCount, int sickDogCount) {
        List<PetOwner> list = new ArrayList<>();
        for (int i = 0; i < petOwnerCount; i++) {
            PetOwner petOwner;
            if (i < sickDogCount) {
                // 拥有病狗的主人
                petOwner = new PetOwner(true);
            } else {
                // 拥有健康狗的主人
                petOwner = new PetOwner(false);
            }
            list.add(petOwner);
        }
        return list;
    }

    /**
     * 观察狗,并思考自己拥有的是否是病狗
     * @param day
     */
    public void watchDogAndThinkTime(int day) {
        for (PetOwner petOwner : petOwners) {
            petOwner.watchOtherDogAndThink(day, petOwners);
        }
    }

    /**
     * 杀狗时间。。。
     *
     * @return 是否有杀狗动作 true:有村民杀了狗。
     */
    public int killDogTime() {
        int killDogEventCount = 0;
        for (PetOwner petOwner : petOwners) {
            if (petOwner.killMyselfDog())
                killDogEventCount++;
        }
        return killDogEventCount;
    }

    public static void main(String[] args) {
        Village village = new Village(50, 10);// 假设一个村庄有50个村民,有3只病狗。

        for (int day = 1; day < 10000; day++) {// 防御式编程,day设置最大,防止编程错误导致无限循环。
            village.watchDogAndThinkTime(day);
            int killDogEventCount = village.killDogTime();
            if (killDogEventCount > 0) {
                System.out.format("今天是第%d天,今天发生了%s次枪击事件!!!", day, killDogEventCount);
                break;
            }
        }
    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值