zoukankan      html  css  js  c++  java
  • zoj 3689 Digging 贪心+01背包

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4972

    题意:总共有N个任务,共有T天。每个任务有ti, si表示需要ti天完成,当能完成任务的情况下(剩余天数t >= ti ),将获得黄金剩余天数t*si。

    思路:

    这道题和普通的01背包稍微有点不同。需要先排序。

    想了一下什么情况下的01背包需要先排序,其实就是动态规划的后效性问题。

    考虑如果只有2个任务,如果这两个任务交换顺序对结果没有影响的情况下,就不需要排序。

    如果交换顺序对结果有影响,就需要排序。

    比如普通的背包,总体积是V,物体A的价值是VA,体积是WA。物体B的价值是VB,体积是WB。

    如果VA+VB<=V,那么A和B都可以放入背包。

    当A先放入B后放入,占的体积是VA+VB,获得收益是WA+WB。

    当B先放入A后放入,占的体积是VA+VB,获得收益是WA+WB,没有变化。那么这种情况就不需要先贪心排序。

    而本题中假设总天数是T,任务A为ta, sa,任务B为tb, sb。如果ta+tb<=T,那么两个任务都可以做完。

    如果先做任务A,再做任务B,获得的收益是T*sa + (T-ta)*sb。

    如果先做任务B,再做任务A,获得的收益是T*sb + (T-tb)*sa。这种情况下两者不同,所以需要先贪心排序。

    由于DP方程为 dp[i][j] = max(dp[i-1][j], dp[i-1][j-node[i].t]+j*node[i].s);

    相当于已经算出了dp[i-1][j-node[i].t]再来计算dp[i][j]。t越大获得的收益越多。所以越后算的即t越大的会获得比较大的收益。

    那么在排序的时候,需要T*sa + (T-ta)*sb < T*sb + (T-tb)*sa,即把小的放前面。

    化简得-ta*sb < -tb*sa。

    如果不清楚可以把DP过程打出来试这两组样例:

    2 10
    1 2
    2 1

    2 10

    2 1

    1 2

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int N, T;
     4 int dp[10010];
     5 struct Node
     6 {
     7     int t, s;
     8 }node[3010];
     9 bool cmp(Node n1, Node n2)
    10 {
    11     return -n1.t*n2.s < -n1.s*n2.t;
    12 }
    13 int main() 
    14 {
    15    // freopen("in.txt", "r", stdin);
    16    // freopen("out.txt", "w", stdout);
    17     while(~scanf("%d%d", &N, &T))
    18     {
    19         for(int i = 1; i <= N; i++)
    20         {
    21             scanf("%d%d", &node[i].t, &node[i].s);
    22         }
    23         sort(node+1, node+1+N, cmp);
    24         memset(dp, 0, sizeof(dp));
    25         int ans = 0;
    26         for(int i = 1; i <= N; i++)
    27         {
    28             for(int j = T; j >= node[i].t; j--)
    29             {
    30                // cout<<i<<" "<<j<<" "<<" "<<node[i].t<<" "<<dp[j]<<" "<<dp[j-node[i].t]+j*node[i].s<<endl;
    31                 dp[j] = max(dp[j], dp[j-node[i].t]+j*node[i].s);
    32             }
    33         }
    34         printf("%d
    ", dp[T]);
    35     }
    36     return 0;
    37 }
  • 相关阅读:
    java 单向链表实现
    super、this
    Java程序员们最常犯的10个错误
    Codeforces-1323D Present
    Codeforces-1323E Instant Noodles
    Codeforces-1312E Array Shrinking
    Codeforces-1327D Infinite Path
    Codeforces-1326D Prefix-Suffix Palindrome
    HDU-5885 XM Reserves
    NTT(快速数论变换)用到的各种素数及原根
  • 原文地址:https://www.cnblogs.com/titicia/p/5355677.html
Copyright © 2011-2022 走看看