摘要:
通过对一个问题两种解法分析,揭示了二分逼近求解的精妙之处
问题描述如下:
给定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