首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > Java相关 >

算法设计:找出诚实的人,该如何解决

2013-10-21 
算法设计:找出诚实的人一个地方有两种人:诚实的人和骗子,诚实的人只说真话,骗子可能说真话也可能说假话,已

算法设计:找出诚实的人
一个地方有两种人:诚实的人和骗子,诚实的人只说真话,骗子可能说真话也可能说假话,已知的是这里诚实的人比骗子要多,而且当地人知道这里其他的人是骗子还是诚实的人。
你来到这里,要求找出所有的骗子,你可以问这里任何的人A关于另外个人B的问题“B是不是骗子?”。设计一个找出所有骗子的算法,但是时间复杂度是O(n)
算法 设计
[解决办法]
写了一个,最坏时间复杂度O(3n)


import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

/**
 * 一个地方有两种人:诚实的人和骗子,诚实的人只说真话,骗子可能说真话也可能说假话,已知的是这里诚实的人比骗子要多,
 * 而且当地人知道这里其他的人是骗子还是诚实的人。
 * 你来到这里,要求找出所有的骗子,你可以问这里任何的人A关于另外个人B的问题“B是不是骗子?”。设计一个找出所有骗子的算法,但是时间复杂度是O(n)
 * 
 * 
 */
public class Test008 {

public static void main(String[] args) {
ArrayList<People> list = new ArrayList<People>();
// init
final int PEOPLE_COUNT = 20;
final int SWINDLER_COUNT = Math.max(1,
new Random().nextInt(PEOPLE_COUNT - 1) / 2);
for (int i = 0; i < SWINDLER_COUNT; ++i) {
list.add(new Swindler());
}
for (int i = 0; i < PEOPLE_COUNT - SWINDLER_COUNT; ++i) {
list.add(new Honester());
}
//打乱顺序
Collections.shuffle(list);
//为方便查看结果,显示序号
for(int i = 0;i < list.size();++i) {
People p = list.get(i);
p.setNum(i);
}
System.out.println("询问前");
System.out.println(list);
//获取骗子序号
ArrayList<Integer> resultList = findSwindlers(list);
System.out.println("询问后,骗子序号:");
System.out.println(resultList);
}

/**
 * 找到一个诚实的人就OK
 * 第一次询问序号0 ~ N-1,检测第一个人是否是骗子(说他是骗子的人数 >= N/2)
 * 如果不是骗子,就可以得到结果
 * 否则从N/2 ~ N-1开始询问,检测第N/2个人是否是骗子(说他是骗子的人数 >= N/4)
 * ...
 * 以此类推,直到找出诚实的人
 * 以上询问时间为N + N/2 + N/4 + N/8 + ... 无限接近O(2n)
 * 最后询问诚实的人时间复杂度为O(n)
 * 故总时间复杂度为O(3n)
 */
static ArrayList<Integer> findSwindlers(ArrayList<People> list) {
boolean isHonester = false;
int start = 0;
int end = list.size();
while(!isHonester) {
int swindlerCount = 0;
People checkPeople = list.get(start);
for(int i = start;i < end;++i) {
People p = list.get(i);
if(p.say(checkPeople)) {
++swindlerCount;
}
}
if(swindlerCount >= (end - start) / 2) {
//骗子
start = (end + start) / 2;
} else {
isHonester = true;
}
}
People honester = list.get(start);
ArrayList<Integer> resultList = new ArrayList<Integer>();
for(int i = 0;i < list.size();++i) {
People p = list.get(i);
if(honester.say(p)) {
resultList.add(i);
}
}
return resultList;
}
}

abstract class People {
protected boolean isSwindler = false;
protected int num;//编号

protected void setNum(int num) {
this.num = num;
}

protected abstract boolean say(People p);
}

class Honester extends People {
public Honester() {
isSwindler = false;
}

@Override
protected boolean say(People p) {
return p.isSwindler;
}

@Override
public String toString() {
return num + "诚实";
}
}

class Swindler extends People {
public Swindler() {
isSwindler = true;
}

@Override
protected boolean say(People p) {
int seed = new Random().nextInt(2);
return seed == 0;
}

@Override
public String toString() {
return num + "骗子";
}
}


[解决办法]
我居然把它做完了,离职了所以闲的蛋疼,数学不好,不要让我求算法复杂度!

package test;

import java.security.SecureRandom;
import java.util.ArrayList;

public class TrustAndLie{
  private static SecureRandom sr=new SecureRandom();

  public static void main(String...args){
    Group unknown=Group.generateSource();
    Group lieGroup=findLieGroup(unknown);
    unknown.removeAll(lieGroup);


    lieGroup.assertLie();
    unknown.assertTrust();
    System.out.println("I got it, Lie count:"+lieGroup.size()+"   Trust count:"+unknown.size());
  }

  private static Group findLieGroup(Group unknown){
    Group sayTrust=new Group();
    Group sayLie=new Group();
    Group lieGroup=new Group();
    while(unknown.size()>0){
      People base=unknown.remove(0);
      for(People people:unknown)
        if(people.test(base)) sayTrust.add(people);
        else sayLie.add(people);
      if(sayLie.size()==sayTrust.size()) return sayLie;
      if(sayTrust.size()>sayLie.size()){
        lieGroup.addAll(sayLie);
        for(People people:sayTrust)
          if(!base.test(people)) lieGroup.add(people);
        return lieGroup;
      }
      lieGroup.add(base);
      lieGroup.addAll(sayTrust);
      unknown.removeAll(sayTrust);
      sayTrust.clear();
      sayLie.clear();
    }
    return lieGroup;
  }

  private static class Group extends ArrayList<People>{
    private static final long serialVersionUID=145658485844788783L;

    public static Group generateSource(){
      Group group=new Group();
      int trust=0;
      int lie=0;
      for(int i=0;i<1000;i++){
        if(sr.nextBoolean()){
          group.add(new Trust());
          trust++;
        }else{
          group.add(new Lie());
          lie++;
        }
      }
      for(int i=0;i<lie+1-trust;i++)
        group.add(new Trust());
      return group;
    }

    public void assertTrust(){
      for(People people:this)
        people.assertTrust();
    }

    public void assertLie(){
      for(People people:this)
        people.assertLie();
    }
  }

  private static class People{
    private boolean trust;

    public People(boolean trust){
      this.trust=trust;
    }

    public boolean test(People people){
      return people.trust;
    }

    public void assertTrust(){
    }

    public void assertLie(){
    }
  }

  private static class Trust extends People{
    public Trust(){
      super(true);
    }

    @Override
    public void assertLie(){
      throw new IllegalArgumentException("You're wrong!");
    }
  }

  private static class Lie extends People{
    public Lie(){
      super(false);
    }

    @Override
    public boolean test(People people){
      return sr.nextBoolean();
    }

    @Override
    public void assertTrust(){
      throw new IllegalArgumentException("You're wrong!");
    }
  }
}

热点排行