zoukankan      html  css  js  c++  java
  • POJ3111 K Best 【最佳牛围栏】二分

    K Best

    Time Limit: 8000MS Memory Limit: 65536K
    Total Submissions: 17073 Accepted: 4286
    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 = {i1, i2, …, 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


    一般我们想到这题应该是贪心,但是看到题目限制的时间八秒,数据也就1e5,贪心应该错了吧(我第一次就是这样写的)。
    其实这道题目是贪心和二分的经典应用。
    sigma(vi) / sigma(wi) >= x {vi∈S, wi∈S}我假设这个成立,所以有
    sigma(vi) - sigma(wi) * x >= 0 {vi∈S, wi∈S},每次去二分我们的x最后就可以得到我们的正确答案。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int maxn = 100010;
    double v[maxn], w[maxn];
    int n, m;
    struct each {
        double sum;
        int id;
    }select[maxn];
    bool cmp(each a, each b) {
        return a.sum > b.sum;
    }
    bool judge(double x) {
        for(int i = 1; i <= n; i++) {
            select[i].sum = v[i] - w[i] * x;
            select[i].id = i;
        }
        sort(select + 1, select + n + 1,cmp);
        double sum = 0;
        for(int i = 1; i <= m; i ++)//只要取前m项大的就行,
            sum += select[i].sum;
        if(sum >= 0)    return true;
        return false;
    }
    int main() {
        while(scanf("%d %d", &n, &m) != EOF) {
            for(int i = 1; i <= n; i++)
                scanf("%lf %lf", &v[i], &w[i]);
            double l = 0, r = 1000000;
            while(r - l >= 1e-7) {
                double mid = (l + r) / 2;
                if(judge(mid)) l = mid;
                else    r = mid;
            }
            cout << select[1].id;
            for(int i = 2; i <= m; i++)//最后一次的最佳开始输出对应的id
                cout << " " << select[i].id;
            cout << endl;
        }
        return 0;
    }
    
    


    最佳牛围栏

    农夫约翰的农场由 N 块田地组成,每块地里都有一定数量的牛,其数量不会少于1头,也不会超过2000头。
    约翰希望用围栏将一部分连续的田地围起来,并使得围起来的区域内每块地包含的牛的数量的平均值达到最大。
    围起区域内至少需要包含 F 块地,其中 F 会在输入中给出。
    在给定条件下,计算围起区域内每块地包含的牛的数量的平均值可能的最大值是多少。

    输入格式
    第一行输入整数 N 和 F ,数据间用空格隔开。
    接下来 N 行,每行输出一个整数,第i+1行输出的整数代表,第i片区域内包含的牛的数目。

    输出格式
    输出一个整数,表示平均值的最大值乘以1000再 向下取整 之后得到的结果。

    数据范围
    1≤N≤100000
    1≤F≤N
    输入样例:
    10 6
    6
    4
    2
    10
    3
    8
    5
    9
    4
    1
    输出样例:
    6500


    按照题意,我们只要找到一个最大区间满足条件就行。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn = 100010;
    int n, m;
    double a[maxn], sum[maxn];
    
    bool judge(double x) {
        for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i] - x;//通过减去一个当前查找的值,减小数的值,其实可有可无。
        double minn = 0;
        for(int i = 0, j = m; j<= n; j++, i++) {
            minn = min(minn, sum[i]);//找到前面的最小值。
            if(sum[j] >= minn)  return true;//如果有一个区间满足立刻return true
        }
        return false;
    }
    int main() {
        scanf("%d %d", &n, &m);
        for(int i = 1; i <= n; i++) scanf("%lf", &a[i]);
        double l = 0, r = 2000;
        while(r - l >= 1e-5) {
            double mid = (l + r) / 2;
            if(judge(mid))  l = mid;
            else    r = mid;
        }
        printf("%d
    ",int(r * 1000));//按照题意输出。
        return 0;
    }
    
  • 相关阅读:
    Java实现 LeetCode 697 数组的度(类似于数组的map)
    Java实现 LeetCode 697 数组的度(类似于数组的map)
    Java实现 LeetCode 697 数组的度(类似于数组的map)
    Java实现 LeetCode 696 计数二进制子串(暴力)
    Java实现 LeetCode 696 计数二进制子串(暴力)
    Java实现 LeetCode 696 计数二进制子串(暴力)
    Java实现 LeetCode 695 岛屿的最大面积(DFS)
    Java实现 LeetCode 695 岛屿的最大面积(DFS)
    PHP serialize() 函数
    PHP print_r() 函数
  • 原文地址:https://www.cnblogs.com/lifehappy/p/12601187.html
Copyright © 2011-2022 走看看