1. 程式人生 > >演算法2.分治演算法 晶片判斷好壞

演算法2.分治演算法 晶片判斷好壞

有n片晶片,已知好晶片比壞晶片至少多1片。
現需要通過測試從中找出1片好晶片,測試方法為:將2片晶片放到測試臺上,2片晶片互相測試並報告測試結果(即好或者壞);其中,好晶片的報告是正確的,壞晶片的報告是不可靠的(即可能正確、也可能錯誤)。
為保證使用較少的測試次數就能從中找出1片好晶片,請設計一個分治演算法解決上述問題。

  1. 演算法設計思路

  2. 晶片進行一一比較可能的結果為(好,好)(好,壞),其中(好,好)包括的可能性為兩片晶片都是好的,也有可能兩片都是壞的。

  3. n奇數:先取出一片晶片,然後將該晶片和其餘的晶片進行一一比較,若比較結果為(好,好)的次數>n/2,則該晶片為好晶片,反之則為壞晶片,將壞晶片刪除後,進行n偶數
  4. n偶數次:晶片兩兩比較,在結果為(好,好)中取出一片另放,以便後續繼續比較,將結果為(好,壞)的都捨去。若最後的晶片片數為偶數,則繼續進行n偶數,若為奇數,則進行n奇數
  5. 若結果剩餘的片數為1或者2,則該晶片為好晶片。
  6. 演算法實現的虛擬碼
    功能描述:在n片晶片中找出好的晶片
    輸入:n>0(晶片總片數),再輸入0,1。0代表壞晶片,1代表好的晶片。其中1的個數大於0的個數
    輸出:已經找到好的晶片,比較的次數count。
```
    int find(n,int a[]){
    count++;
    if n=1 or n=2,return true count;
    else
if n%2!=0 EvenNum(n,int Nnew[]); else if n%2=0 OddNum(n,int Nnew[]); } 功能描述:n為偶數時,任意兩片晶片進行一一比較,將比較結果為(好,好)的其中一片取出放入新的陣列中,其餘結果刪除。 輸入:n,int Nnew[] 輸出:新的n,新的陣列Nnew2[]; int EvenNum(n,int Nnew[]){ int k=0; for (int i=0;i<n;i+=2){ if Nnew[i]=Nnew[i+1] Nnew2[k]=Nnew[i] k++; return
find(k,Nnew2[]) } } 功能描述:n為奇數時,取出其中任意一片晶片,將該晶片與其他晶片一一比較,若結果為(好,好)的次數大於n/2,則該晶片為好晶片,反之刪除該晶片後進行n偶數。 輸入:n,int Nnew[]; 輸出:好晶片和比較次數count或者新的陣列Nnew3[]; int OddNum(n, int Nnew[]){ int k=0; for (int i=1;i<n;i++){ if Nnew[0]=Nnew[i] k++; } if k>n/2 輸出比較次數count else for (int j=1;j<n;j++) Nnew3[j-1]=Nnew[j] return find() }
  1. 實現程式碼
    import java.util.*;
    public class main{
        public static void main(String []args){
            Scanner in=new Scanner(System.in);
            while (true){
                count=0;
                System.out.println("輸入晶片的總數n");
                System.out.println("輸入0或者1,0代表壞晶片,1代表好晶片");
                System.out.println("其中1的個數大於0的個數");
                int n=in.nextInt();
                int a[] =new int[n];
                for (int i=0;i<n;i++){
                    a[i]=in.nextInt();
                }
                count=find(n,a);
                System.out.println("使用方法n奇數和n偶數的總次數"+count);
                System.out.println();
            }
        }
        static int count=0;
        static int find(int n,int a[]){
            if (n==1||n==2)
                return count;
            else if (n%2==0)//n=偶數
                count=EvenNum(n,a);
            else if (n%2!=0)//n=奇數
                count=OddNum(n,a);
            count++;
            return count;
        }
        private static int OddNum(int n, int[] Nnew) {//奇數
            int k=0;//定義一個確定記錄(好,好)的次數k
            for (int i=1;i<n;i++){
                if (Nnew[0]==Nnew[i])//將第一個和其餘晶片比較
                    k++;//記錄(好,好)的次數
            }
            int[] Nnew3 = new int[n-1];//當k<n/2,建立陣列儲存新的
            if (k>=n/2)
                return count;//找到
            else {
                for (int j=1;j<n;j++)
                    Nnew3[j-1]=Nnew[j];//刪除第一個,
                return find(n-1, Nnew3);//返回偶數
            }
        }
        static int EvenNum(int n,int Nnew[]){//偶數
            int k=0;//記錄返回後晶片的個數
            int[] Nnew2 = new int[n/2];
            for (int i=1;i<n;i+=2){//晶片兩兩檢驗,將結果相同的取一個錄入新的陣列。
                if (Nnew[i-1]==Nnew[i]){
                    Nnew2[k]=Nnew[i];
                    k++;
                }
            }
            return find(k, Nnew2);//返回find,並根據k的奇偶性重新判斷
        }
    }
  1. 演算法執行結果及計算時間複雜度分析
    這裡寫圖片描述
    T(n)=T(n/2)+n/2 O(n)=log N
  2. 體會
    編寫過程中犯了很多的錯誤,其中比較多的錯誤都是由於自己粗心大意,也就是基礎理解不到位,例如判斷一個整數是否為偶數老是愛寫成/,導致了結果出現了很大的差池,最終在除錯的時候發現了這個致命的錯誤。編寫程式的時候,先把思路寫下來,然後按照這個思路進行編寫,感覺會比較順手,要不然像以前一樣,邊寫邊想,老是停停頓頓,導致效率不是很高。程式寫完後,測試花費了比較多的時間。很多都是要通過除錯來驗算自己的預算值。