zoukankan      html  css  js  c++  java
  • 工作计划 题解

    题目描述

    Mark 在无意中了解到了 Elf 的身世。在和 James 商量过之后,好心的他们 打算送 Elf 返回故乡。然而,去往 Gliese 的飞船票价高的惊人,他们暂时还付 不起这笔费用。经过一番考虑,Mark 打算去额外做一些工作来获得收入。 经过一番调查,Mark 发现有 N 个工作可以做。做第 i 件工作所需要的时间为 Di,同时也需要一个能力值 Ci 才可以去做,每件工作都可以在任意时间开 始,也可以做任意多次。所有的工作给付的报酬都是一致的。同时,有 S 个课 程可以参加,我们认为今天是第 0 天,第 i 个课程在第 Mi 天开始,持续时间 为 Li 天,课程结束之后能力值会变为 Ai。现在 Mark 的能力值为 1。Mark 只 能做工作到第 T 天(因为那是飞船起飞的日子)。

    他想知道期限内他最多可以做多少件工作,好决定未来的打算。于是他找到 了 applepi。でも、applepi は彼女と一緒に楽しむことが大切だ,所以这个任务 就交给你了。

    输入输出格式

    输入格式:

    第一行包含三个空格分隔的整数 T,S,N。 之后 S 行,每行三个整数 M,L,A,描述一个课程。 之后 N 行,每行两个整数 C,D,描述一件工作。

    输出格式:

    一个整数,表示 Mark 最多可以做多少件工作。

    输入输出样例

     
    输入样例 输出样例

    10 1 2
    3 2 5
    4 1
    1 3

    6


     

    说明

    第 0 天至第 2 天做第二件工作 1 次,第 3 天至第 4 天参加课程,能力值变为 5。然后第 5 天至第 9 天做第一件工作 5 次。第 10 天 Mark 不可以继续做工作了。所以 Mark 最多做 6 次工作。

    对于 20% 的数据,T,S,N≤10。

    对于 50% 的数据,T,N≤1000。

    对于 100% 的数据,S≤100,M,L≤10000,A≤100。N≤10000,C≤100, D≤10000,T≤10000。

    题解

      根据题目,我们尝试用动态规划来解决这道题。

      状态:f[i][j]第i天时能力值为j的最大工作量

      转移:

        

      对于上面的转移,我们有一下的一些优化:

      • 对于每一个能力值i,我们都可以找到消耗时间最少且需要能力不超过i的工作,记作po[i]。
      • 对于每一个在 i 时刻结束,将能力值改变为j 的课程的开始时间可以记作ke[i][j]。在输入时通过ke[m + l][a] = m获得。
      • 对于每一个阶段(天数)我们可以得到一个最大的工作记作量记作g[i]表示第 i 天的工作量最大为g[i]。通过g[i] 我们可以快速地转移上课那种情况的状态。
      • 我们可以用maxc表示出现过的最大的能力值(减少状态)。

      由此我们的状态转移方程就变成了这样:

        

      初始值: 

          这是这道题最神奇的地方了,他的初始值分为两部分:

        f[0][1]  = 0表示的是第0天时能力值为1,且无法工作。

        对于其余的f[][]则要赋初值为负无穷。

      为什么呢?因为对于这道题中有很多的状态是无效状态,对于无效状态f[i][j]是无法在第 i 天之前得到 j 的能力值却在 i 天的时候有用 j 的能力值去做了工作(即对答案产生了贡献),比如说在输入样例中,f[2][4] , f[2][5]就是无效状态。我们对比分析一下有效状态和无效状态之间的关系,我们发现有效状态只会由有效状态转移得到,那么我们的问题就是找到最开始的有效状态是什么了,根据题目中的“现在 Mark 的能力值为 1”和“我们认为今天是第 0 天”我们可以确定最初的有效状态是f[0][1] = 0。又因为我们的g数组要求当前阶段的所有状态的最大值(包括无效状态),所以我们要消除掉所有无效状态对答案的影响,注意到我们的有效状态只会通过工作这种转移方式转移到无效状态,而这种转移方式对答案的改变每次只+1,而其余的转移都是取min和取max,所以我们就可以像上面那样赋初值。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    int ke[10005][105], g[10005];
    int f[10005][105];
    int po[10005];
    int main()
    {
    //    freopen("wrk.in", "r", stdin);
    //    freopen("wrk.out", "w", stdout);
        memset(f, 128, sizeof(f));
        memset(g, 128, sizeof(g));
        memset(po, 127, sizeof(po));
        int t, s, n, m, l, a, c, d, maxc = 0;
        scanf("%d%d%d", &t, &s, &n);
        for(int i = 1; i <= s; ++ i)
        {
            scanf("%d%d%d", &m, &l, &a);
            maxc = max(maxc, a);
            ke[m + l][a] = max(ke[m + l][a], m);
        }
        for(int i = 1; i <= n; ++ i)
        {
            scanf("%d%d", &c, &d);
            maxc = max(maxc, c);
            po[c] = min(po[c], d);
        }
        for(int i = 2; i <= maxc; ++ i)    
            po[i] = min(po[i], po[i - 1]);
        f[0][1] = 0;
        for(int i = 1; i <= t; ++ i)
            {
                for(int j = 1; j <= maxc; ++ j)
                    if(ke[i][j])
                        f[i][j] = max(f[i][j], g[i - ke[i][j] + 1]);
                for(int j = 1; j <= maxc; ++ j)
                {
                    if(i - po[j] >= 0)    f[i][j] = max(f[i - po[j]][j] + 1, f[i][j]);
                    f[i][j] = max(f[i][j], f[i - 1][j]);
                    g[i] = max(g[i], f[i][j]);
                }
            }
        printf("%lld
    ", g[t]);
    }
  • 相关阅读:
    [Poi2000]病毒
    [Zjoi2015]诸神眷顾的幻想乡
    P1663 山
    P1837 单人纸牌
    P6584 重拳出击
    CF460C Present
    10.5 学习笔记
    多项式学习笔记(一) FFT
    NOIP 2020 游记
    uva 经典习题选做(dp专项)
  • 原文地址:https://www.cnblogs.com/2020pengxiyue/p/9338384.html
Copyright © 2011-2022 走看看