假定一个解并判断是否可行 POJ1064
C(x) = Ai/x的总和是否大于或等于k
#include<iostream>
#include<cstdio>
#include<math.h>
#include<string>
using namespace std;
int N,K;
double a[10005];
bool C(double x)
{
int num = 0;
for(int i = 0;i < N;i++)
{
num += (int)(a[i]/x);
}
return num >= K;
}
int main()
{
cin >> N >> K;
for(int i = 0;i < N;i++)
{
cin >> a[i];
}
double left = 0,right = 2000000; //二分搜索上限至少是最大值的两倍 经验!
for(int i = 0;i < 100;i++)
{
double mid = (left+right)/2;
if(C(mid)) left = mid;
else right = mid;
}
printf("%.2f\n",floor(left*100)/100);最小两位取整的做法
}
每次判断的时间复杂度为O(N)
最大化最小值
POJ2456
C(d)=可以安排牛的位置使得任意的牛的间距都不小于d
1.对房子的位置x进行排序
2.把第一头牛放入第一个房子
3.如果第i头牛放入Xj的话,第i+1头牛就要放入Xj+d <=Xk的最小k中
#include<iostream>
#include<cstdio>
#include<math.h>
#include<string>
#include<algorithm>
using namespace std;
int N,M;
int a[10005];
bool C(int x)
{
int last = 0;
for(int i = 1;i < M;i++)
{
int cnt = last + 1;
while(cnt < N && a[cnt] - a[last] < x)
{
cnt++;
}
if(cnt == N)
return false;
last = cnt;
}
return true;
}
int main()
{
cin >> N >> M;
for(int i = 0;i < N;i++)
{
cin >> a[i];
}
sort(a,a+N);
int left = 0,right = 2000000;
for(int i = 0;i < 100;i++)
{
int mid = (left+right)/2;
if(C(mid)) left = mid;
else right = mid;
}
printf("%d\n",left);
}
最大化平均值
有n个物品的重量和价值分别是wi和vi。从中选出k个物品使得单位重量的价值最大
用贪心将性价比最高的选出是不可行的,只能用二分。
sum v / sum w >= x 推出公式v - x*w >= 0
因此可以对公式进行排序贪心选取了
#include<iostream>
#include<cstdio>
#include<math.h>
#include<string>
#include<algorithm>
using namespace std;
int n,k;
int y[10005];
int w[10005];
int v[10005];
bool cmp(int a,int b)
{
return a > b;
}
bool c(int mid)
{
double sum = 0;
for(int i = 0;i < n;i++)
{
y[i] = v[i] - mid * w[i];//公式为Vi-xWi >= 0
}
sort(y,y+n,cmp);
for(int i = 0;i < k;i++)
{
sum += y[i];
}
return sum >= 0;
}
int main()
{
cin >> n >> k;
for(int i = 0;i < n;i++)
{
cin >> w[i] >> v[i];
}
double left = 0;
double right = 1000000;
for(int i = 0; i < 100;i++)
{
double mid = (left+right)/2;
if(c(mid))
{
left = mid;
}
else
{
right = mid;
}
}
printf("%.2f\n",left);
}
折半枚举(双向搜索)
POJ NO.2785
#include<iostream>
#include<cstdio>
#include<math.h>
#include<string>
#include<algorithm>
using namespace std;
int N;
int A[4005];
int B[4005];
int C[4005];
int D[4005];
int AB[4005*4005];
int main()
{
cin >> N;
for (int i=0;i<N;i++) cin>>A[i]>>B[i]>>C[i]>>D[i];
for(int i = 0;i < N;i++)
for(int j = 0;j < N;j++)
AB[i*N + j] = A[i] + B[j];
sort(AB,AB+N*N);
long res = 0;
for(int i = 0;i < N;i++)
for(int j = 0;j < N;j++)
{
int cd = -(C[i] + D[j]);
res += upper_bound(AB,AB+N*N,cd) - lower_bound(AB,AB+N*N,cd);
}
cout << res << endl;
}
POJ3104
第一次见需要推公式的二分,还是做题少啊。
先列出公式,X为用吹风机的时间,Y为自然风干的时间,我们这里需要找出mid使得mid = x+y;
y+x*k >= Ai 两个式子相减就是k-1 !不是k!
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<algorithm>
typedef long long ll;
using namespace std;
ll n, k;
ll a[1000005];
bool C(ll x)
{
ll crt=0;
for (int i = 0; i <n; i++)
{
if (a[i] > x)
{
crt += (a[i] - x + (k - 2)) / (k - 1);
if (crt > x) return true;
}
}
return false;
}
int main()
{
while (scanf("%lld", &n) != EOF)
{
for (int i = 0; i < n; i++)
scanf("%lld", &a[i]);
scanf("%lld", &k);
sort(a, a + n);
if (k == 0 || k == 1)
printf("%d\n", a[n - 1]);
else {
ll l = 0, h = 0x3f3f3f3f;
while (h - l > 1)
{
ll mid = (l + h) / 2;
if (C(mid)) l = mid;
else h = mid;
}
printf("%lld\n", h);
}
}
return 0;
}
求a,b之间有多少个斐波那契额数,二分思想nb呀
import java.math.BigInteger;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
BigInteger a[]=new BigInteger[10500];
a[1]=BigInteger.valueOf(1);
a[2]=BigInteger.valueOf(2);
for(int i=3;i<10500; i++)
a[i]=a[i-1].add(a[i-2]);
BigInteger n,b;
while(cin.hasNextBigInteger()){
n=cin.nextBigInteger();
b=cin.nextBigInteger();
if(n.equals(BigInteger.ZERO) && b.equals(BigInteger.ZERO))
break;
int sum1=0,sum2=0;
int low,high,mid;
low=1;high=10500;
while(low<=high){
mid=(low+high)/2;
if(a[mid].compareTo(n)==0){
sum1=mid-1;
break;
}
else if(a[mid].compareTo(n)<0)
low=mid+1;
else high=mid-1;
}
if(sum1==0&&!n.equals(BigInteger.valueOf(1)))sum1=high;
low=1;high=10500;
while(low<=high){
mid=(low+high)/2;
if(a[mid].compareTo(b)==0){
sum2=mid;
break;
}
else if(a[mid].compareTo(b)<0)
low=mid+1;
else high=mid-1;
}
if(sum2==0&&!b.equals(BigInteger.valueOf(1)))sum2=high;
System.out.println(sum2-sum1);
}
}
}