工作计划 题解

题目描述

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,所以我们就可以像上面那样赋初值。

代码

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int ke[10005][105], g[10005];
 5 int f[10005][105];
 6 int po[10005];
 7 int main()
 8 {
 9 //    freopen("wrk.in", "r", stdin);
10 //    freopen("wrk.out", "w", stdout);
11     memset(f, 128, sizeof(f));
12     memset(g, 128, sizeof(g));
13     memset(po, 127, sizeof(po));
14     int t, s, n, m, l, a, c, d, maxc = 0;
15     scanf("%d%d%d", &t, &s, &n);
16     for(int i = 1; i <= s; ++ i)
17     {
18         scanf("%d%d%d", &m, &l, &a);
19         maxc = max(maxc, a);
20         ke[m + l][a] = max(ke[m + l][a], m);
21     }
22     for(int i = 1; i <= n; ++ i)
23     {
24         scanf("%d%d", &c, &d);
25         maxc = max(maxc, c);
26         po[c] = min(po[c], d);
27     }
28     for(int i = 2; i <= maxc; ++ i)    
29         po[i] = min(po[i], po[i - 1]);
30     f[0][1] = 0;
31     for(int i = 1; i <= t; ++ i)
32         {
33             for(int j = 1; j <= maxc; ++ j)
34                 if(ke[i][j])
35                     f[i][j] = max(f[i][j], g[i - ke[i][j] + 1]);
36             for(int j = 1; j <= maxc; ++ j)
37             {
38                 if(i - po[j] >= 0)    f[i][j] = max(f[i - po[j]][j] + 1, f[i][j]);
39                 f[i][j] = max(f[i][j], f[i - 1][j]);
40                 g[i] = max(g[i], f[i][j]);
41             }
42         }
43     printf("%lld\n", g[t]);
44 }

猜你喜欢

转载自www.cnblogs.com/2020pengxiyue/p/9338384.html