不光是查找值!二分搜索

来自《挑战程序设计竞赛》

1.一般解法

二分搜索,是最常见又最简单的查找算法。在求最优解的问题上也非常有用。让我们考虑一下“求满足某个条件C(x)的最小的x”这一问题。对于任意满足C(x)的x,如果所有的x'>=x也满足C(x'),就可以利用二分搜索求最小的x。首先将区间左端点初始化为不满足C(x)的值,右端点初始化为满足C(x)的值,取中点判断是否满足,缩小区间范围,直到(lb,ub]足够小为止,最后ub就是要求的最小值。
下面给出几个例题

2.Poj1064

1.题目原文

Cable master
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 38554 Accepted: 8240

Description

Inhabitants of the Wonderland have decided to hold a regional programming contest. The Judging Committee has volunteered and has promised to organize the most honest contest ever. It was decided to connect computers for the contestants using a "star" topology - i.e. connect them all to a single central hub. To organize a truly honest contest, the Head of the Judging Committee has decreed to place all contestants evenly around the hub on an equal distance from it. 
To buy network cables, the Judging Committee has contacted a local network solutions provider with a request to sell for them a specified number of cables with equal lengths. The Judging Committee wants the cables to be as long as possible to sit contestants as far from each other as possible. 
The Cable Master of the company was assigned to the task. He knows the length of each cable in the stock up to a centimeter,and he can cut them with a centimeter precision being told the length of the pieces he must cut. However, this time, the length is not known and the Cable Master is completely puzzled. 
You are to help the Cable Master, by writing a program that will determine the maximal possible length of a cable piece that can be cut from the cables in the stock, to get the specified number of pieces.

Input

The first line of the input file contains two integer numb ers N and K, separated by a space. N (1 = N = 10000) is the number of cables in the stock, and K (1 = K = 10000) is the number of requested pieces. The first line is followed by N lines with one number per line, that specify the length of each cable in the stock in meters. All cables are at least 1 meter and at most 100 kilometers in length. All lengths in the input file are written with a centimeter precision, with exactly two digits after a decimal point.

Output

Write to the output file the maximal length (in meters) of the pieces that Cable Master may cut from the cables in the stock to get the requested number of pieces. The number must be written with a centimeter precision, with exactly two digits after a decimal point. 
If it is not possible to cut the requested number of pieces each one being at least one centimeter long, then the output file must contain the single number "0.00" (without quotes).

Sample Input

4 11
8.02
7.43
4.57
5.39

Sample Output

2.00

Source

2.解题思路

条件C(x)是可以得到K条长度为x的绳子,

C(x)=(floor(L[i]/x)的总和是否大于等于K)。

利用上述一般解法,二分搜索即可解决。

3.AC代码

#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include<cmath>
#include<bitset>
#include<sstream>
using namespace std;
#define INF 0x7fffffff
#define maxn 10005

int N,K;
double L[maxn];

bool C(double x)
{
    int num=0;
    for(int i=0;i<N;i++){
        num+=(int)(L[i]/x);
    }
    return num>=K;
}

void solve()
{
    double lb=0,ub=INF;
    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()
{
    scanf("%d%d",&N,&K);
    for(int i=0;i<N;i++){
        cin>>L[i];
    }
    solve();
    return 0;
}

3.Poj2456

1.题目原文

Aggressive cows
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 11470 Accepted: 5618

Description

Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0 <= xi <= 1,000,000,000). 

His C (2 <= C <= N) cows don't like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?

Input

* Line 1: Two space-separated integers: N and C 

* Lines 2..N+1: Line i+1 contains an integer stall location, xi

Output

* Line 1: One integer: the largest minimum distance

Sample Input

5 3
1
2
8
4
9

Sample Output

3

Hint

OUTPUT DETAILS: 

FJ can put his 3 cows in the stalls at positions 1, 4 and 8, resulting in a minimum distance of 3. 

Huge input data,scanf is recommended.

Source

2.解题思路

C(d):可以安排牛的位置是的任意的牛的间距都不小于d
接下来用贪心法便可求解
1.对牛舍的位置x进行排序
2.第一头牛放在x[0]处
3.如果第i头牛放在了x[j]处,那么i+1头牛就要放入满足x[j]+d<=x[k]的最小的x[k]中。
最后利用上述一般解法即可求解。

3.AC代码

#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include<cmath>
#include<bitset>
#include<sstream>
using namespace std;
#define INF 0x7fffffff
#define maxn 100005

int N,M;
int x[maxn];

bool C(int d)
{
    int last=0;
    for(int i=1;i<M;i++){
        int crt=last+1;
        while(crt<N&&x[crt]-x[last]<d){
            crt++;
        }
        if(crt==N) return false;
        last=crt;
    }
    return true;
}

void solve()
{
    sort(x,x+N);
    int lb=0,ub=INF;
    while(ub-lb>1){
        int mid=(lb+ub)/2;
        if(C(mid)) lb=mid;
        else ub=mid;
    }
    printf("%d\n",lb);
}

int main()
{
    scanf("%d%d",&N,&M);
    for(int i=0;i<N;i++){
        cin>>x[i];
    }
    solve();
    return 0;
}

4.最大化平均值

1.题目原文

有n个物品的重量和价值分别是w[i]和v[i]。从中选出k个物品使得单位重量的价值最大。
数据范围
1<=k<=n<=10^4
1<=w[i],v[i]<=10^6

2.解题思路

定义C(x):可以选择使得单位重量的价值不小于x。
原问题就变成了求满足C(x)的最大的x。
假设我们选择的物品的集合是S,那么它们单位重量的价值是
∑v[i]/∑w[i]
∑v[i]/∑v[i]>=x变形得∑(v[i]-x*w[i])>=0.
因此可以对v[i]x*w[i]的值进行排序贪心的进行选取
因此就变成了C(x)=((v[i]-x*w[i])从大到小排列中前k个的和不小于0)。
每次判断的时间复杂度为O(nlogn)。

3.代码

#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include<cmath>
#include<bitset>
#include<sstream>
using namespace std;
#define INF 0x7fffffff
#define maxn 10005

int n,k;
int w[maxn],v[maxn];

double y[maxn];//y=v-x*w;

bool C(double x)
{
    for(int i=0;i<n;i++){
        y[i]=v[i]-x*w[i];
    }
    sort(y,y+n);

    //计算数组y中从大到小前k个数的和
    double sum=0;
    for(int i=0;i<k;i++){
        sum+=y[n-i-1];
    }
    return sum>=0;
}

void solve()
{
    double lb=0,ub=INF;
    for(int i=0;i<100;i++){
        double mid=(lb+ub)/2;
        if(C(mid)) lb=mid;
        else ub=mid;
    }
    printf("%.2f\n",ub);
}

int main()
{
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++){
        cin>>w[i]>>v[i];
    }
    solve();
    return 0;
}

5.Poj2976

1.题目原文

Dropping tests
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 9977 Accepted: 3492

Description

In a certain course, you take n tests. If you get ai out of bi questions correct on test i, your cumulative average is defined to be

.

Given your test scores and a positive integer k, determine how high you can make your cumulative average if you are allowed to drop any k of your test scores.

Suppose you take 3 tests with scores of 5/5, 0/1, and 2/6. Without dropping any tests, your cumulative average is . However, if you drop the third test, your cumulative average becomes .

Input

The input test file will contain multiple test cases, each containing exactly three lines. The first line contains two integers, 1 ≤ n ≤ 1000 and 0 ≤ k < n. The second line contains n integers indicating ai for all i. The third line contains n positive integers indicating bi for all i. It is guaranteed that 0 ≤ ai ≤ bi ≤ 1, 000, 000, 000. The end-of-file is marked by a test case with n = k = 0 and should not be processed.

Output

For each test case, write a single line with the highest cumulative average possible after dropping k of the given test scores. The average should be rounded to the nearest integer.

Sample Input

3 1
5 0 2
5 1 6
4 2
1 2 7 9
5 6 7 9
0 0

Sample Output

83
100

Hint

To avoid ambiguities due to rounding errors, the judge tests have been constructed so that all answers are at least 0.001 away from a decision boundary (i.e., you can assume that the average is never 83.4997).

Source

2.解题思路

和上题一样,注意精度(abs(ub-lb)<1e-4)还有四舍五入。
四舍五入采用(int)(lb*100+0.5)。注意+0.5这一方法,可以轻松处理四舍五入的情况。

3.AC代码

#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include<cmath>
#include<bitset>
#include<sstream>
using namespace std;
#define INF 0x7fffffff
#define maxn 1005

int n,k;
int a[maxn],b[maxn];

double y[maxn];//y=100*a-x*b

bool C(double x)
{
    for(int i=0;i<n;i++){
        y[i]=a[i]-x*b[i];
    }
    sort(y,y+n);

    //计算数组y中从大到小前n-k个数的和
    double sum=0;
    for(int i=0;i<n-k;i++){
        sum+=y[n-i-1];
    }
    return sum>=0;
}

void solve()
{
    double lb=0,ub=1;
    while(abs(ub-lb)>1e-4){
        double mid=(lb+ub)/2.0;
        if(C(mid)) lb=mid;
        else ub=mid;
    }
    printf("%d\n",(int)(lb*100+0.5));
}

int main()
{
    while(cin>>n>>k){
        if(n==0&&k==0) break;
        for(int i=0;i<n;i++){
            cin>>a[i];
        }
        for(int i=0;i<n;i++){
            cin>>b[i];
        }
        solve();
    }

    return 0;
}

6.POJ3111

1.题目原文

Language:
K Best
Time Limit: 8000MS Memory Limit: 65536K
Total Submissions: 9138 Accepted: 2374
Case Time Limit: 2000MS Special Judge

Description

Demy has n jewels. Each of her jewels has some value vi and weight wi.

Since her husband John got broke after recent financial crises, Demy has decided to sell some jewels. She has decided that she would keep k best jewels for herself. She decided to keep such jewels that their specific value is as large as possible. That is, denote the specific value of some set of jewels S = {i1i2, …, ik} as

.

Demy would like to select such k jewels that their specific value is maximal possible. Help her to do so.

Input

The first line of the input file contains n — the number of jewels Demy got, and k — the number of jewels she would like to keep (1 ≤ k ≤ n ≤ 100 000).

The following n lines contain two integer numbers each — vi and wi (0 ≤ vi ≤ 106, 1 ≤ wi ≤ 106, both the sum of all vi and the sum of all wi do not exceed 107).

Output

Output k numbers — the numbers of jewels Demy must keep. If there are several solutions, output any one.

Sample Input

3 2
1 1
1 2
1 3

Sample Output

1 2

Source

Northeastern Europe 2005, Northern Subregion

2.解题思路

题目意思不解释,和上题一样。挑战简直就是一个模板库……
第一次忘记对最终结果排序,WA。第二次,for循环里是100,TLE,搜了题解,改为50,成功AC,但是所需时间也太长了……。

3.AC代码

#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<string>
#include<set>
#include<vector>
#include<cmath>
#include<bitset>
#include<stack>
#include<sstream>
#include<deque>
#include<utility>
using namespace std;
#define INF 0x7fffffff
#define maxn 100005
typedef pair<double,int> P;

int n,k;
int v[maxn],w[maxn];
P y[maxn];

int opt[maxn];

bool C(double x)
{
    for(int i=0;i<n;i++){
        y[i]=P(v[i]-x*w[i],i);
    }
    sort(y,y+n);

    double sum=0;
    for(int i=0;i<k;i++){
        sum+=y[n-1-i].first;
    }

    return sum>=0;
}

void solve()
{
    double lb=0,ub=INF;
    for(int i=0;i<50;i++){
        double mid=(lb+ub)/2;
        if(C(mid)){
            lb=mid;
        }
        else ub=mid;
    }
    for(int i=0;i<k;i++){
        opt[i]=y[n-1-i].second+1;
    }
    sort(opt,opt+k);

    for(int i=0;i<k-1;i++){
        printf("%d ",opt[i]);
    }
    printf("%d\n",opt[k-1]);
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF){
        for(int i=0;i<n;i++){
            scanf("%d%d",&v[i],&w[i]);
        }
        solve();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值