演算法2.分治演算法 晶片判斷好壞
阿新 • • 發佈:2019-02-13
有n片晶片,已知好晶片比壞晶片至少多1片。
現需要通過測試從中找出1片好晶片,測試方法為:將2片晶片放到測試臺上,2片晶片互相測試並報告測試結果(即好或者壞);其中,好晶片的報告是正確的,壞晶片的報告是不可靠的(即可能正確、也可能錯誤)。
為保證使用較少的測試次數就能從中找出1片好晶片,請設計一個分治演算法解決上述問題。
演算法設計思路
晶片進行一一比較可能的結果為(好,好)(好,壞),其中(好,好)包括的可能性為兩片晶片都是好的,也有可能兩片都是壞的。
- n奇數:先取出一片晶片,然後將該晶片和其餘的晶片進行一一比較,若比較結果為(好,好)的次數>n/2,則該晶片為好晶片,反之則為壞晶片,將壞晶片刪除後,進行n偶數
- n偶數次:晶片兩兩比較,在結果為(好,好)中取出一片另放,以便後續繼續比較,將結果為(好,壞)的都捨去。若最後的晶片片數為偶數,則繼續進行n偶數,若為奇數,則進行n奇數
- 若結果剩餘的片數為1或者2,則該晶片為好晶片。
- 演算法實現的虛擬碼
功能描述:在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()
}
- 實現程式碼
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的奇偶性重新判斷
}
}
- 演算法執行結果及計算時間複雜度分析
T(n)=T(n/2)+n/2 O(n)=log N - 體會
編寫過程中犯了很多的錯誤,其中比較多的錯誤都是由於自己粗心大意,也就是基礎理解不到位,例如判斷一個整數是否為偶數老是愛寫成/,導致了結果出現了很大的差池,最終在除錯的時候發現了這個致命的錯誤。編寫程式的時候,先把思路寫下來,然後按照這個思路進行編寫,感覺會比較順手,要不然像以前一樣,邊寫邊想,老是停停頓頓,導致效率不是很高。程式寫完後,測試花費了比較多的時間。很多都是要通過除錯來驗算自己的預算值。