天平称球如何代码实现

久伴说来太遥远,看着背影渐远,不如怀念。

问题描述:现在有n(n>=2)个球,n个球外观一模一样,但是重量有区别,其中有且仅有一个球的重量比其它n-1个球要重,现在有一个天平,天平是完好无损的,问最少需要称多少次才能确定哪个球的重量较重?

灵感来源:http://www.cnblogs.com/dolphin0520/archive/2012/10/02/2707762.html(博客园:海子)

这个问题以前在面试的时候经常遇到,不过记得当时好像没有要求写代码,好像需要推导公式...

一般在遇到在这个问题的时候,思维会很固定的想到去将n个球平分,每次平分下去称量比较。前两天偶尔又碰见这个问题,博主的思路是将n个球分成2组或者3组来解决。

个人按照思路归纳了一遍,如果想要写代码实现统一的实现,肯定要有一个固定的模板。于是我的做法就是n>=2的时候,都是分成3组来解决:

声明:试验证明,平分成2组比较次数远多于3组。

推导思路:(主要这么推导写代码方便)将n个球分成3组。

n=2  :     (1,1,0)            最少比较1次                                 

n=3 :      (1,1,1)            最少比较1次                                  

n=4:       (2,1,1)            最少比较1次    最多比较2次                               

n=5:       (2,2,1)            最少比较1次    最多比较2次                                 

n=6:       (2,2,2)            最少比较2次    最多比较2次                                 

n=7:       (3,2,2)            最少比较2次    最多比较2次

n=8:       (3,3,2)            最少比较2次    最多比较2次

n=9:      (3,3,3)             最少比较2次    最多比较2次

n=10:    (4,3,3)             最少比较2次    最多比较3次

n=11:    (4,4,3)             最少比较2次     最多比较3次

规律:设3组的球个数分别是:(i,j,k)

那么:如果 n%3=0   则  i=n/3  否则  i=n/3+1

         剩下 n=n-i;

对于j:如果 n%2=0  则  j=n/2  否则 j=n/2+1

对于k: k=n-i-j

如此下来,在n>=2的时候,将n个球分成3组,每组的个数由以上规则确定出来!

可以看出来,在这么分组后,每组的数据组成大概都会有规律:

当n%3=0,   分组为(n/3,n/3,n/3)

当n%3!=0,  分组为(x,x,y)或者(x,y,y)

按照分为3组的思路,最少次数应该为  3<=n  即 x=n1/3 取整

java代码:(递归)

从键盘录入一个数字,按回车即可显示出分组情况以及最后的结果,建议n>3,因为代码没有添加太多数字不合格方面的校验。

import java.util.Scanner;
/**
 * there are many balls .find the weighter ball
 * get the time that find the weighter ball(max time)
 * */
public class WeightestBall {
 
      /**
       * assign group 将n个数分成m组
       * */
      private static void assignGroup(int[] array,int n,int m){
            if(n<2)
             return;
            if(m==3){
             if(n%3==0){
              array[0]=array[1]=array[2]=n/3;
             }else{
              array[0]=n/3+1;
              /*剩余的2组继续通过回调赋值*/
              assignGroup(array,n-(n/3+1),2);
             }
            }
            if(m==2){
             if(n%2==0){
              array[1]=array[2]=n/2;
             }else{
              array[1]=n/2+1;
              array[2]=n-array[1]-array[2];
             }
            }
            System.out.println("
assgin group result");
            for(int i=0;i<array.length;i++){
                System.out.print(array[i]+" ");
            }
      }
      /**
       * compare and get the time 找出最重一个球所需的次数
       * */
      private static int getMaxWeight(int[] array){
           int result=0;
           /*1 sort: small->big */
//           sort(array);
           int i=array[0],j=array[1],k=array[2];
           if(i==j&&j==k){
               result=1+f(i);
           }
           else{
               /*这里会有区别:这里可以求出得到质量不同球的最大/最小次数:此处求最小次数*/
               if(f(i)<=f(k))
                  result=1+f(i);
               else
                  result=1+f(k);
           }
           System.out.println("
need the least "+result+" times");
           return result;
      }
      /**
       * f():关键的递归回调函数:按照同样的规则逐层求出所需的次数
       * */
      private static int f(int n){
           int result=0;
           if(n==2)
            return 1;
           if(n==1)
            return 0;
           int[] array=new int[3];
           assignGroup(array,n,3);
           result=getMaxWeight(array);
           return result;
      }
      /**
       * sort 排序:按照从小到大的顺序排列数组
       * */
      private static void sort(int[] array){
           /*select sort:选择排序*/
           for(int i=0;i<array.length;i++){
            int min=i;
            for(int j=i+1;j<array.length;j++){
              if(array[min]>array[j]){
                  min=j;
              }
            }
            int temp=array[i];
            array[i]=array[min];
            array[min]=temp;
           }
           System.out.println("
sort result");
           for(int i=0;i<array.length;i++){
            System.out.print(array[i]+" ");
           }
      }
      public static void main(String[] args) {
           System.out.println("please input the ball number:");
           @SuppressWarnings("resource")
           int num=new Scanner(System.in).nextInt();
           int[] array=new int[3];
           if(num>2){
               assignGroup(array,num,3);
               getMaxWeight(array);
           }
      }
}

明确思路,代码看起来就很简单了。

执行效果:

欢迎有不同看法的同仁指正。转载请注明链接。

原文地址:https://www.cnblogs.com/dftencent/p/5378620.html