例題:金塊問題
老板有一袋金塊(共n塊,n是2的冪(n>=2) ),最優秀的員工得到其中最重的一塊,最差的員工得到其中最輕的一塊。假設有一台比較重量的儀器,請你用最少的比較次數找出最重和最輕的金塊。
這個問題其實就是輸入n個數,找出最大和最小數的問題。
解決問題的策略
蠻力策略:對金塊逐個進行比較查找。(掃描數組一輪,尋找最大和最小的數。)該策略需要進行(n-1)次的比較才能得到Max和min。
分治法(二分法)策略:問題可以簡化為在n個數里面尋找最大和最小值。
(1)將數據等分為兩組(兩組數據的個數可能相差1),目的是分別選取其中的最大(小)值。
(2)遞歸分解直到每組元素的個數<=2,則可以簡單地找到其中的最大(小)值。
(3)回溯時合並子問題的解,在兩個子問題的解中大者取大,小者取小,即合並為當前問題的解。
1 #include<stdio.h> 2 #include<time.h> 3 #include<stdlib.h> 4 int maxMin(int *a,int i,int j,int *max,int *min); 5 int main() 6 { 7 int *a; 8 int i,n; 9 int max,min; 10 11 scanf("%d",&n); 12 a=(int *)malloc(sizeof(int)*n); 13 srand((unsigned int)time(0)); 14 for(i=0;i<n;i++) a[i]=rand()%91+10; 15 for(i=0;i<n;i++) 16 { 17 printf("%d ",a[i]); 18 if((i+1)%5==0) printf("\n"); 19 } 20 printf("\n\n"); 21 maxMin(a,0,n-1,&max,&min); 22 printf("%d %d\n",max,min);/**/ 23 return 0; 24 } 25 /*--------------------------------------------------- 26 函數名稱:maxMin 27 函數功能:在數組a的區間[i,j]范圍內尋找一個最大值和一個最小值並通過指針*max和*min返回。 28 -----------------------------------------------------*/ 29 int maxMin(int *a,int i,int j,int *max,int *min) 30 { 31 int mid; 32 int lmax,lmin,rmax,rmin; 33 if(j==i) { *max=a[i]; *min=a[i]; return 0;} 34 else if(j-i==1) 35 { 36 if(a[i]>a[j]) {*max=a[i];*min=a[j];return 0;} 37 else {*max=a[j];*min=a[i];return 0;} 38 } 39 else 40 { 41 mid=i+(j-i)/2; 42 maxMin(a,i,mid,&lmax,&lmin); 43 maxMin(a,mid+1,j,&rmax,&rmin); 44 if(lmax>rmax) *max=lmax; 45 else *max=rmax; 46 if(lmin<rmin) *min=lmin; 47 else *min=rmin; 48 } 49 return 0; 50 }
由該問題演變出來的另一個問題:尋找數組當中最大的兩個數和最小的兩個數。下面的代碼實現了該算法,同樣采用的是二分策略。【該算法稍有欠缺:對假如最大數或最小數有相同的多個值,可能得到的最大(小)值與次大(小)值是一樣的。】
1 #include<stdio.h> 2 #include<time.h> 3 #include<stdlib.h> 4 int maxMin2(int *a,int i,int j,int *max1,int *max2,int *min1,int *min2); 5 int max(int a,int b); 6 int min(int a,int b); 7 int main() 8 { 9 int *a; 10 int i,n; 11 int max1,max2,min1,min2; 12 13 scanf("%d",&n); 14 a=(int *)malloc(sizeof(int)*n); 15 srand((unsigned int)time(0)); 16 for(i=0;i<n;i++) a[i]=rand()%91+10; 17 for(i=0;i<n;i++) 18 { 19 printf("%d ",a[i]); 20 if((i+1)%5==0) printf("\n"); 21 } 22 printf("\n\n"); 23 maxMin2(a,0,n-1,&max1,&max2,&min1,&min2); 24 printf("%d %d\n%d %d\n",max1,max2,min1,min2);/**/ 25 return 0; 26 } 27 int maxMin2(int *a,int i,int j,int *max1,int *max2,int *min1,int *min2) 28 { 29 int mid,t; 30 int lmax1,lmax2,lmin1,lmin2,rmax1,rmax2,rmin1,rmin2; 31 if(j-i==2) 32 { 33 *max1=max(a[j],max(a[i],a[i+1])); 34 *min1=min(a[j],min(a[i],a[i+1])); 35 t=a[i]+a[j]+a[i+1]; 36 *max2=t-*max1-*min1; 37 *min2=*max2; 38 return 0; 39 } 40 else if(j-i==1) 41 { 42 if(a[i]>a[j]){*max1=a[i];*max2=a[j]; *min1=a[j];*min2=a[i];return 0;} 43 else{*max1=a[j];*max2=a[i]; *min1=a[i];*min2=a[j];return 0;} 44 } 45 else 46 { 47 mid=i+(j-i)/2; 48 maxMin2(a,i,mid,&lmax1,&lmax2,&lmin1,&lmin2); 49 maxMin2(a,mid+1,j,&rmax1,&rmax2,&rmin1,&rmin2); 50 if(lmax1>rmax1) 51 { 52 *max1=lmax1; 53 if(lmax2>rmax1) *max2=lmax2; 54 else *max2=rmax1; 55 } 56 else 57 { 58 *max1=rmax1; 59 if(lmax1>rmax2) *max2=lmax1; 60 else *max2=rmax2; 61 } 62 if(lmin1<rmin1) 63 { 64 *min1=lmin1; 65 if(lmin2<rmin1) *min2=lmin2; 66 else *min2=rmin1; 67 } 68 else 69 { 70 *min1=rmin1; 71 if(lmin1<rmin2) *min2=lmin1; 72 else *min2=rmin2; 73 } 74 } 75 return 0; 76 } 77 int max(int a,int b) 78 { return a>b?a:b; } 79 int min(int a,int b) 80 { return a<b?a:b; }
對於該算法的缺陷,暫時還不知道如何解決了呵呵
