zoukankan      html  css  js  c++  java
  • POJ 3111 K Best

    二分,排序,贪心。

    最优比率生成树,可以二分$+$贪心来实现,不过这样做精度不行。

    如果是这样一个问题,该如何解决:问你$n$个里面选择$k$个,能否使得$frac{{sumlimits_{j = 1}^k {{v_{{i_j}}}} }}{{sumlimits_{j = 1}^k {{w_{{i_j}}}} }} ≥ x$。

    上述问题等价于问你:$n$个里面选择$k$个,能否使得$sumlimits_{j = 1}^k {({v_{{i_j}}} - x×{w_{{i_j}}})}  ≥ 0$。

    也就是说,我们需要令${f_i} = {v_i} - x×{w_i}$,按照${f_i}$从大到小排序,选择前$k$个计算和$sum$。

    如果$sum≥0$,也就是说$frac{{sumlimits_{j = 1}^k {{v_{{i_j}}}} }}{{sumlimits_{j = 1}^k {{w_{{i_j}}}} }} ≥ x$成立;否则不成立。

    因为这个问题是遵循单调性的,$x$越大可能性越小,因此只要二分$x$,然后验证就可以了。时间复杂度$O(50*n*log n)$。

    特别要注意的是精度问题:

    $[1].$计算$sum$的时候,最后要加上一个$eps$,我在这卡了很久精度。

    $[2].$二分的话差不多$50$次就可以了,$100$次$TLE$了,也没有必要进行$100$次,因为实际上是只要$log {10^7}$次。

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<queue>
    #include<stack>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    const double pi=acos(-1.0),eps=1e-6;
    void File()
    {
        freopen("D:\in.txt","r",stdin);
        freopen("D:\out.txt","w",stdout);
    }
    template <class T>
    inline void read(T &x)
    {
        char c = getchar(); x = 0;while(!isdigit(c)) c = getchar();
        while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar();  }
    }
    
    const int maxn=100010;
    struct X { int v,w;}s[maxn];
    int n,k,ans[maxn];
    struct XX {double num; int id;}t[maxn];
    double Max;
    
    bool cmp(XX a,XX b){ return a.num>b.num; }
    
    bool check(double x)
    {
        for(int i=1;i<=n;i++)
        {
            t[i].num=1.0*s[i].v-x*s[i].w;
            t[i].id=i;
        }
        sort(t+1,t+1+n,cmp);
    
        double sum=0;
        for(int i=1;i<=k;i++) sum=sum+t[i].num;
        
        if(sum+eps>=0) 
        {
            for(int i=1;i<=k;i++) ans[i]=t[i].id;
            return 1;
        }
        return 0;
    }
    
    int main()
    {
        while(~scanf("%d%d",&n,&k))
        {
            for(int i=1;i<=n;i++)
                scanf("%d%d",&s[i].v,&s[i].w);
    
            double L=0.0,R=10000000.0;
            int t=50;
            while(t--)
            {
                double mid=(L+R)/2;
                if(check(mid)) L=mid;
                else R=mid;
            }
    
            for(int i=1;i<=k;i++)
            {
                printf("%d",ans[i]);
                if(i<k) printf(" "); else printf("
    ");
            }
        }
        return 0;
    }
  • 相关阅读:
    Codeforces 1291 Round #616 (Div. 2) B
    总结
    刷新DNS解析缓存+追踪+域名解析命令
    数学--数论--Hdu 5793 A Boring Question (打表+逆元)
    Lucene.net(4.8.0) 学习问题记录六:Lucene 的索引系统和搜索过程分析
    LeetCode 117 Populating Next Right Pointers in Each Node II
    LeetCode 116 Populating Next Right Pointers in Each Node
    test test
    LeetCode 115 Distinct Subsequences
    LeetCode 114. Flatten Binary Tree to Linked List
  • 原文地址:https://www.cnblogs.com/zufezzt/p/5831586.html
Copyright © 2011-2022 走看看