zoukankan      html  css  js  c++  java
  • Poj 2976 Dropping tests(01分数规划 牛顿迭代)

    Dropping tests
    Time Limit: 1000MS Memory Limit: 65536K
    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
    Stanford Local 2005

    /*
    裸的01分数规划问题.
    令∑a[i]/∑b[i]=ans. 
    则∑a[i]-∑b[i]*ans=0. 
    二分一个ans.
    然后用a[i]-b[i]*ans取前k大检验.
    只能去感性的认识orz...
    并不会证明.. 
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define eps 1e-7
    #define MAXN 1001
    using namespace std;
    double ans,a[MAXN],b[MAXN],sum,tmp[MAXN];
    int n,m,k;
    bool check(double x)
    {
        double tot=0;
        for(int i=1;i<=n;i++) tmp[i]=a[i]-x*b[i];
        sort(tmp+1,tmp+n+1,greater<double>());
        for(int i=1;i<=n-k;i++) tot+=tmp[i];
        if(tot>=0) return true;
        else return false;
    }
    void slove()
    {
        double l=0,r=1e4,mid;
        while(l<=r)
        {
            mid=(l+r)/2.0;
            if(check(mid)) l=mid+eps,ans=mid;
            else r=mid-eps;
        }
        printf("%.0f
    ",ans*100);
        return ;
    }
    int main()
    {
        while(scanf("%d%d",&n,&k))
        {
            if(!n&&!k) break;
            sum=ans=0;
            for(int i=1;i<=n;i++) scanf("%lf",&a[i]);
            for(int i=1;i<=n;i++) scanf("%lf",&b[i]);
            slove();
        }
        return 0;
    }
    /*
    发现这题牛顿迭代可做吖.
    网上的题解都是二分01规划的.
    我就写个牛顿迭代的吧orz(虽然二分的写过).
    先选一个估计值s0.
    我们能保证这个答案是单调的.
    假设上次迭代的ans为s1,
    则存在n-k个元素使s1=∑(ai/bi),
    变形可得到∑ai-s2*∑bi=0,
    令ans[i]=a[i]-b[i]*s0.
    取前n-k大统计一个答案.
    可知必存在n-k个元素使∑ansi=∑ai-s1*∑bi=0,
    所以当我们按ans排序并取前n-k个元素作为求其∑ans时,
    ∑ansi显然是>=0的,
    然后s1=(∑ai-∑ansi)/∑bi)<=(∑ai/∑bi)=s2(i<=n-k).
    即此迭代过程是收敛的,当等号成立时,s即为答案.
    有些地方还是有点想不通毕竟弱吖orz. 
    */
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define MAXN 1001
    #define eps 1e-7
    using namespace std;
    double ans,sum,tmp[MAXN];
    int n,m,k;
    struct data{double a,b,ans;}s[MAXN];
    bool cmp(const data &x,const data &y)
    {
        return x.ans>y.ans;
    }
    void slove()
    {
        double suma=0,sumb=0,s0=0,s1=0;
        for(int i=1;i<=k;i++) suma+=s[i].a,sumb+=s[i].b;
        s0=suma/sumb;
        while(abs(s0-s1)>eps)
        {
            s1=s0;suma=sumb=0;
            for(int i=1;i<=n;i++) s[i].ans=s[i].a-s[i].b*s0;
            sort(s+1,s+n+1,cmp);
            for(int i=1;i<=k;i++) suma+=s[i].a,sumb+=s[i].b;
            s0=suma/sumb;
        }
        printf("%.0f
    ",s0*100);
        return ;
    }
    int main()
    {
        while(~scanf("%d%d",&n,&k))
        {
            if(!n&&!k) break;
            sum=ans=0;k=n-k;
            for(int i=1;i<=n;i++) scanf("%lf",&s[i].a);
            for(int i=1;i<=n;i++) scanf("%lf",&s[i].b);
            slove();
        }
        return 0;
    }
  • 相关阅读:
    构建业务用例
    CentOS 7使用Redis Cluster
    pymysql.err.OperationalError: (1054, "Unknown column 'aa' in 'field list'")(已解决)
    Flask框架实现登录注册功能(mysql数据库)
    C#实现登录功能(连接SQLServer数据库)
    大数据智能加工系统——纸上原型分析
    Windows环境下启动Redis报错:Could not create server TCP listening socket 127.0.0.1:6379: bind: 操作成功完成。(已解决)
    HBase数据库基础操作
    决策树——非正常企业数目预测
    MongoDB启动报错:Unrecognized option: storage try 'mongod --help' for more information(已解决)
  • 原文地址:https://www.cnblogs.com/nancheng58/p/10068108.html
Copyright © 2011-2022 走看看