今天看挑战程序设计看到了二分的知识,觉得那是相当的神奇啊啊啊啊,没有之一。。。
下面来总结下今天过了的4道二分的题目。
POJ 1064 Cable master
题意:大概意思就是说给你n根绳子,要在这n根绳子中剪K段,每段一样长,问最长每段为多少
思路:很简单的初级二分嘛,枚举下每段绳子的长度,然后用这个长度去看看每段绳子能剪几段,加起来够不够K,枚举是采用二分的,所以是logn级别,判断是n,所以复杂度是
n*logn
源码:
#include<cstdio>
#include<cmath>
int n,k;
double L[10005];
bool C(double d)
{
int num=0;
for(int i=0;i<n;i++)
{
num+=(int)(L[i]/d);
}
return num>=k;
}
void slove()
{
//freopen("debug\\in.txt","r",stdin);
double lb=0,ub=99999999;
for(int i=0;i<100;i++)
{
double mid=(lb+ub)/2;
if(C(mid))lb=mid;
else ub=mid;
}
printf("%.2f\n",floor(ub*100)/100);
}
int main()
{
//freopen("debug\\in.txt","r",stdin);
while(scanf("%d%d",&n,&k)==2)
{
for(int i=0;i<n;i++)
{
scanf("%lf",&L[i]);
}
slove();
}
return 0;
}
POJ 2456
题意:就讲的是有n个房子,要在这n个房子中放m头牛,使相邻两头牛间的距离最大
思路:这道题看似是贪心,但是如果仅仅是一个个去比较的话会比较麻烦,这里用到了二分,我们首先想到二分的次数越多,精度会越高,放到题目中,则是越接近答案
我们就可以枚举两头牛间的距离,如果刚好能放下m头牛,且最小的距离小于d的话,那么我们就向上届继续二分,这里直接贴板即可,这种题目叫做最大化最小值
下面是源码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,c;
long long x[100005];
bool C(long long d)
{
int last=0;
for(int i=1;i<c;i++)
{
int next=last+1;
while(next<n&&x[next]-x[last]<d)
next++;
if(next==n)return false;
last=next;
}
return true;
}
void Slove()
{
sort(x,x+n);
long long lb=0;
long long ub=1000000009;
while(ub-lb>1)
{
long long mid=(ub+lb)/2;
if(C(mid))lb=mid;
else ub=mid;
}
printf("%lld\n",lb);
}
int main()
{
while(scanf("%d%d",&n,&c)==2)
{
for(int i=0;i<n;i++)
{
scanf("%lld",&x[i]);
}
Slove();
}
return 0;
}
POJ3258
题意:这道题讲跟上面那道题是一样的,就是n+2个点,删去m个点,使得相邻两石头最短距离最大,这道题联系上面那道题可以转化为n+2中放N+2-m头牛的问题,那么又回到上面那道题的解法了
下面是源码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long x[50010];
long long l,n,m;
bool C(long long d)
{
int last=0;
for(int i=1;i<n+2-m;i++)
{
int next=last+1;
while(next<n+2&&x[next]-x[last]<d)
next++;
if(next==n+2)return false;
last=next;
}
return true;
}
void Slove()
{
sort(x,x+n+2);
long long lb=0,ub=1000000009;
while(ub-lb>1)
{
long long mid=(lb+ub)/2;
if(C(mid))lb=mid;
else ub=mid;
}
printf("%lld\n",lb);
}
int main()
{
//freopen("debug\\in.txt","r",stdin);
while(scanf("%lld%lld%lld",&l,&n,&m)==3)
{
for(int i=1;i<=n;i++)
scanf("%lld",&x[i]);
x[0]=0;
x[n+1]=l;
Slove();
}
return 0;
}