Cable master POJ - 1064
【浮点数二分】
一般题目会要求输出相应的精度,而这类题目就容易错在这里。可以通过人为的控制循环来达到所要求的精度,或者设立相应的终止条件。
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e4+5;
double pie[N];
int n,k;
int main()
{
while(scanf("%d%d",&n,&k)!=EOF)
{
double left=0,right=inf;//区间足够大
for(int i=1;i<=n;i++)
scanf("%lf",&pie[i]);
for(int i=1;i<=100;i++)
{
double mid=(left+right)/2;
int num=0;
for(int j=1;j<=n;j++)
num+=(int)(pie[j]/mid);
if(num>=k)
left=mid;
else
right=mid;
}
printf("%.2f\n",floor(right*100)/100);//先乘100,然后向下取整,可以直
// 接把百分位后面的位数舍弃,再除以100,即可保留2位小数。
}
return 0;
}
Aggressive cows POJ - 2456
【最大值最小化问题】
大概思路,二分枚举可能距离,然后验证是否满足。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e5+5;
const int maxn=1e9+5;
int x[N];
int n,c;
bool check(int dis)
{
int last=1,cnt=last+1;//从第一个地方开始安排
for(int i=2;i<=c;i++)
{
while(cnt<=n&&x[cnt]-x[last]<dis)
cnt++;
last=cnt;
if(cnt==n+1)//如果能找到,那么cnt必定<=n
return false;
}
return true;
}
int main()
{
while(scanf("%d%d",&n,&c)!=EOF)
{
for(int i=1;i<=n;i++)
scanf("%d",&x[i]);
sort(x+1,x+1+n);
int left=0,right=maxn;
while(left<=right)
{
int mid=(left+right)>>1;
if(check(mid))
left=mid+1;
else
right=mid-1;
}
printf("%d\n",right);
}
return 0;
}
hdu4430
题目要求满足条件的两个数,这时就要选择对哪个数进行二分。
解题策略是:根据n的取值和等比数列求和公式,可以大概估计出r的取值范围,为1~40。同时,有了r的取值,就可以通过通过开方的途径大概求出k的上界,然后在对k进行二分。即对r进行枚举,每次都对k进行一次二分。
这样就能保证在确定一个量的前提下,对另一个量进行二分,保证二分是在单调的情况下进行的。
当有多个量时,应该考虑固定一个看另外几个。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,r,k;
ll solve(ll x,ll y)
{
ll res=0,num=1;
for(int i=1;i<=y;i++)
{
num*=x;
res+=num;
}
if(res==n||res==n-1)//求最佳的r和k值
{
if(x*y<r*k)
{
k=x;
r=y;
}
else if(x*y==r*k&&r>y)
{
k=x;
r=y;
}
}
return res;
}
int main()
{
while(scanf("%lld",&n)!=EOF)
{
k=n-1,r=1;//k=n-1会错误,因为中间可以放1个,为了使k*r最小,当n=18,就会发现错误
for(int i=2;i<=40;i++)//根据n的最大值和等比数列求和大概可以估计r的取值范围
{
ll left=2,right=pow(n,1.0/i);//当r取不同值时,k对应的范围
while(left<=right)//对k进行二分
{
ll mid=(left+right)>>1;
ll tm=solve(mid,i);
if(tm>n)
right=mid-1;
else
left=mid+1;
}
}
printf("%lld %lld\n",r,k);
}
return 0;
}