zoukankan      html  css  js  c++  java
  • 编程之美挑战赛复赛B题

    【题目大意】

    Alice新开了一家公司,它的下面有两个项目,分别需要N1和N2个人来完成。现在有N个人前来应聘,于是Alice通过面试来决定他们中的哪些人会被录用。

    Alice在面试中,会仔细考察他们能如何为公司的项目带来收益。她给每个人打了两个分值Q1和Q2,表示他加入第一个和第二项目分别能带来的收益值。同时,她也会仔细考察他们每个人的缺点,并且给每人打了另两个分值C1和C2,表示他们进入每个项目可能带来的负面效应。Alice心目中的最优决策是,在决定好录用哪些人以及每个人在哪个项目下工作之后,他们为公司带来的收益总和,除以他们为项目带来的负面效应总和,这个比值要最大。你能帮他计算出在最优决策下,这个比值为多少吗?

    前来应聘的人数总是大于等于两个项目需求人数的总和,因此Alice一定会恰好招N1+N2个人,分配给第一个项目N1个人,分配给第二个项目N2个人,没有人会同时属于两个项目。

    【分析】

             题目要求的是 SUM(Q)/SUM(C) 的最大值,假设最大值为ans , 则在最优情况下  SUM(Q)/SUM(C)=ans  ===>   SUM(Q)=ans*SUM(C)=SUM(ans*C)
                 ==>  SUM(Q)-SUM(ans*C)=0  ==>  SUM(Q-ans*C)=0
             看来关键就在于  SUM(Q-ans*C) 了,如果 SUM(Q-ans*C)>0 则说明 ans 还可以在一定的限度内增加,使相减后的和再减小趋近于0。由于和最小为0,即使 Qi-ans*Ci 都小于0,也不会出现 SUM(Q-ans*C)<0 的情况。对于某一固定的 ans ,SUM(Q-ans*C) 的值也会应为人员的选取不同而不同,但是可以肯定的是只要确定某种选择方案,SUM(Q-ans*C) 的值一定随 ans 的增大而减小;根据前面的说明,要使 ans 尽可能增大,对于每个 ans 的SUM(Q-ans*C)就要尽可能大,这里就要用到动态规划了。

            dp[i][j]  (j<=i) 表示前 i 个人,其中 j个人到项目 2 中,不多于 i-j 个人到项目1中。p[i]=pair(Q1-ans*C1,Q2-ans*C2)
                dp[i][j]=max{dp[i-1][j]+(i-j<=n1)*p[i].first,dp[i-1][j-1]+p[i].second}    ( j<i && j<=n2)
           边界:   dp[i][0]=dp[i-1][0]+(i<=n1)*p[i].first   (i个人全进项目1,乘(i<=n1)是为了看项目1如否还可以加人)
                dp[i][i] = dp[i-1][i-1]+p[i].second;     (i个人全进项目2,必须满足条件 (i<=n2) ,可以加入项目2)

                       SUM(Q-ans*C) 的最大值为 max{ dp[j][n2] }  (j>=n1+n2, j<=n)

            由于 ans 对 SUM(Q-ans*C) 的影响的单调的 (SUM(Q-ans*C) 总是用DP求出尽可能大的值),ans 越大,SUM(Q-ans*C)的最大值 就会减少 。所以要做的就是二分 ans ,如果 SUM(Q-ans*C) 大于 0,可以提高下限,如果 SUM(Q-ans*C) 等于0,并不能说明 ans 达到最优解,有可能是超过最优解,所以要减小上限,最优解定在上下限内;这样多做几次二分(有限次数),就可以夹逼求出 ans 的最优解。

       

         附上别人的代码,我也是看这代码有所启发的。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cmath>
     5 #include <map>
     6 #include <string>
     7 #include <cstring>
     8 #include <sstream>
     9 #include <algorithm>
    10 
    11 using namespace std;
    12 
    13 const int MAXN = 505;
    14 
    15 int n, n1, n2;
    16 int q1[MAXN], c1[MAXN], q2[MAXN], c2[MAXN];
    17 pair<double, double> a[MAXN];
    18 double f[MAXN][MAXN];
    19 bool ok(double ans)
    20 {
    21     for (int i = 1; i <= n; ++i) {
    22         a[i] = make_pair(q1[i] - ans * c1[i], q2[i] - ans * c2[i]);
    23     }
    24     sort(a + 1, a + n + 1);
    25     reverse(a + 1, a + n + 1);
    26     double res = 0;
    27     f[0][0] = 0;
    28     for (int i = 1; i <= n; ++i) {
    29         f[i][0] = f[i - 1][0] + (i <= n1) * a[i].first;
    30         for (int j = 1; j < i && j <= n2; ++j) {
    31             f[i][j] = max(f[i - 1][j] + (i - j <= n1) * a[i].first, f[i - 1][j - 1] + a[i].second);
    32         }
    33         if (i <= n2) f[i][i] = f[i - 1][i - 1] + a[i].second;
    34     }
    35     for (int i = n1 + n2; i <= n; ++i)
    36         res = max(res, f[i][n2]);
    37     return res > 0;
    38 }
    39 void work()    
    40 {
    41     scanf("%d%d%d", &n, &n1, &n2);
    42     for (int i = 1; i <= n; ++i) {
    43         scanf("%d%d%d%d", &q1[i], &c1[i], &q2[i], &c2[i]);
    44     }
    45     double f = 0, r = 20000;
    46     for (int tmp = 0; tmp < 70; ++tmp) {
    47         double mid = (f + r) / 2;
    48         if (ok(mid)) f = mid;
    49             else r = mid;
    50     }
    51     printf("%.6f\n", (f+r)/2);
    52 }
    53 int main()
    54 {
    55     int cases;
    56     scanf("%d", &cases);
    57     for (int tcase = 1; tcase <= cases; ++tcase) {
    58         printf("Case #%d: ", tcase);
    59         work();
    60     }
    61     return 0;
    62 }
  • 相关阅读:
    Windows Azure Cloud Service (14) 使用Windows Azure诊断收集日志记录数据
    Windows Azure Cloud Service (13) 用Visual Studio 2010 将应用程序部署到Windows Azure平台
    Windows Azure Cloud Service (15) 多个VM Instance场景下如何处理ASP.NET Session
    Windows Azure Storage (5) Windows Azure Drive
    Windows Azure Storage (7) 使用工具管理Windows Azure Storage
    SQL Azure(二) SQL Azure vs SQL Server
    webbrowser的自动提交
    提取视频的背景声音的软件
    Listview列排序的bug原因
    两个奇怪的问题
  • 原文地址:https://www.cnblogs.com/wuminye/p/3034642.html
Copyright © 2011-2022 走看看