摘要:
通過對一個問題兩種解法分析,揭示了二分逼近求解的精妙之處
問題描述如下:
給定N( 1 <= N <= 100000) 個數,求往N個中數取C(2 <=C< N)個數,使C個數之間兩兩之差的最小值在同類情況下是最大的。
sample:
N = 5, C = 3;
N個數為: 1,2,8,4,9
解的情況為: 1,8,4; 最小值為 3。
其他同類情況可以為1,2,9 or 1,2,4 etc,但是其最小值均為1,不是最佳解。
第一種解法:
對 N個數進行子集樹回溯,然後對每種情況挑出最小值,然後再和maxnum比較,最後出結果。但是這種解法不好地方在於N的個數太大,深搜會出現runtime error。
第二種解法:
在0----num[n-1]之間取一值, 假設其為最佳解,和N個數的兩兩值差進行比較,再統計有多少個值差在假設值之上,若統計值大於等於C則把假設值降低,再進行判斷,反之則提高數值.在提高和降低假設值的過程需要用到二分尋找.所需要的時間為nlogn,遠遠高效於回溯的2^n
相關代碼如下:
//代碼粘得比較不可觀;
#include <stdio.h>
int a[100000];
int n,m;
bool find(int v)
{
int pre=a[0],c=0;
for(int i=1;i<n;i++)
{
if(a[i]-pre>=v)
{
c++;
pre=a[i];
}
}
if(c>=m)
return true;
else
return false;
}
int cmp(const void *x,const void *y)
{
return *(int *)x-*(int *)y;
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
m--;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
qsort(a,n,sizeof(a[0]),cmp);
int left=0,right=a[n-1],mid;
while(left<=right)
{
mid=(left+right)/2;
if(find(mid))
left=mid+1;
else
right=mid-1;
}
printf("%d/n",left-1);
return 0;
}
相關的二分法練習如下:
http://acm.pku.edu.cn/JudgeOnline/problem?id=3388
http://acm.pku.edu.cn/JudgeOnline/problem?id=2456
http://acm.zju.edu.cn/show_problem.php?pid=2002