回 帖 发 新 帖 刷新版面

主题:[讨论]关于从13个乒乓球中挑1个次品的算法

原题是在13个乒乓球中有1个次品,外表和正品一样,但重量不同,不知道是轻是重,试给出一个算法,用不带砝码的天平以尽可能少的次数将次品挑出来.


我查了些文章大约知道怎么挑,但是用程序代码模拟不出来.以下是我用二分查找法求解的.

/**
* 从13个乒乓球中挑次品
*/
import java.io.*;
public class PickBalls{ 
  public static void main(String[] args){
    System.out.println("*********挑选乒乓球次品*********");
    System.out.println("*            Emote             *");
    System.out.println("********************************");
    BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
    int count=0;
    try{
      System.out.println("请输入球数:");
      count=Integer.valueOf(in.readLine()).intValue();
    }catch(Exception e){
        System.out.println("输入有误退出.");System.exit(0);
    }
    if(count<1) {System.out.println("输入有误退出.");System.exit(0);}
    int[] balls=new int[count+1];
    //for(int i=0;i<count;i++) balls[i]=1;
    int rand=(int)(Math.random()*count+0.5);//使次品球可能为最后一个.
    balls[(rand==0)?rand=1:rand]=1;
   // balls[count]=1;
    System.out.println("将球排好并编号,随机使"+rand+"号球为次品球(1仅代表次品不做挑选依据).");
    for(int i=1;i<=count;i++) System.out.print(i+"  ");
    System.out.println();
    for(int i=1;i<=count;i++) {String s="";if(i>=9) s=" "; System.out.print(balls[i]+"  "+s);}
    System.out.println();
    //2分查找法
    System.out.println("使用二分查找法挑选次品.");
 
    int low=1,high=count,middle=0;
    while(low<high){
         middle=(int)(low+high)/2;
         System.out.println(low+","+middle+" -> "+middle+","+high);
         if(low==middle) {System.out.println("查找结束.次品球号为:"+low);break;}
         if(PickBalls(balls,low,middle,high)>0) 
           {System.out.println("两边球重量不一样.将左边按序号分两组再测试.");
               int r=PickBalls(balls,low,(int)(low+middle)/2,middle);
               if(r>0) {high=middle;System.out.println("左边分两组测试重量不相等,次品在左边"+low+","+middle);}//左边再分两次测仍然不一样,则说明次品在左部分左半边
          //如果左部分分两边测试结果一样,那么结果就在右部分
          else {low=middle;System.out.println("左边分两组测试重量相等,次品在右边"+middle+","+high);}
         }
         //球数为奇数,并且最后一个球为次品
         else{ System.out.println("前面"+(count-1)+"个球重量相等,最后一个球"+count+"为次品");break;}     
    //    t++;if(t>10) break;
    }
  }
  //两部分相等返回0,否则返回1
  public static int PickBalls(int[] balls,int from,int mid,int to){
      int t1=0,t2=0;
      for(;from<mid;from++) t1+=balls[from];
      for(;mid<to;mid++) t2+=balls[mid];
      if(t1==t2) return 0;
    else return 1; 
  }
}

我数据结构学的不是很好,还请大家给一个好的解法,谢谢

回复列表 (共3个回复)

沙发

因为是13个球且只有一个是次品。我想到一个方法:大概的思路如下

将13个元素分成5组,前4个组每组里面有3个元素,第5组里面只有一个元素
前4组中随便拿一组跟剩下3组都做比较,如果没发现有问题的话,第5组的那个一定是次品了,如果有一组与其他的3组不一样,说明第5组那个元素的好的。
假设是第1组有次品存在。将第一组的所有元素跟第5组元素比较就行了。结果就出来了。

板凳

楼上的,假如最多只能称三次呢?

3 楼

分成  4 4 5 
先比较4 4,
    4 4  若一样重,责必在5中
                对5划分成 2 2 1,比较2 2
                                  若一样,责必是剩下的一个
                                  若不一样,设2 2 中元素分别为a1,a2和b1,b2
                                            拿a1 b1 比较
                                            再a1  b2 比较
                                             共四种情况:
                                              a1=b1,a1=b2:则a2为次品
                                              a1!=b1,a1!=b2:则a1必为次品
                                              a1=b1,a1!=b2:则b2为次品
                                              a1!=b1,a1=b2:则b1必为次品
4 4  若不一样:把这8个元素分成 3 3 2
重复上述过程(此处省略)


最坏情况下要比较5次才能得出结果

我是菜鸟,指能到这个地步了,请教楼上最多3次是怎么弄的,谢谢你

我来回复

您尚未登录,请登录后再回复。点此登录或注册