1003吉哥系列故事——临时工计划
Time Limit: 1.0 Seconds Memory Limit: 32768K
俗话说一分钱难倒英雄汉,高中几年下来,吉哥已经深深明白了这个道理,因此,新年开始存储一年的个人资金已经成了习惯,不过自从大学之后他不好意思再向大人要压岁钱了,只能把唯一的希望放到自己身上。可是由于时间段的特殊性和自己能力的因素,只能找到些零零碎碎的工作,吉哥想知道怎么安排自己的假期才能获得最多的工资。
已知吉哥一共有m天的假期,每天的编号从1到m,一共有n份可以做的工作,每份工作都知道起始时间s,终止时间e和对应的工资c,每份工作的起始和终止时间以天为单位(即天数编号),每份工作必须从起始时间做到终止时间才能得到总工资c,且不能存在时间重叠的工作。比如,第1天起始第2天结束的工作不能和第2天起始,第4天结束的工作一起被选定,因为第2天吉哥只能在一个地方工作。
现在,吉哥想知道怎么安排才能在假期的m天内获得最大的工资数(第m+1天吉哥必须返回学校,m天以后起始或终止的工作是不能完成的)。
Input
第一行是数据的组数T;
每组数据的第一行是2个正整数:假期时间m和可做的工作数n;
接下来n行分别有3个正整数描述对应的n个工作的起始时间s,终止时间e,总工资c。
[Technical Specification]
1<=T<=1000
9<m<=100
0<n<=1000
s<=100, e<=100, s<=e
c<=10000
Output
对于每组数据,输出吉哥可获得的最高工资数。
SampleInput
1
10 5
1 5 100
3 10 10
5 10 100
1 4 2
6 12 266
SampleOutput
102
一打眼看这道题,以为是贪心,但是后来仔细一分析,发现是dp
用dp[i]记录前i天的最大收入,那么dp[m]就最后的解。详细的解析,看代码
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int N = 110;
vector <int> s[N]; //用来存储每个结束时间,所对应的开始时间,根据输入,一个结束时间可能会有对应几个开始时间,和几个工资
vector <int> c[N]; //用来存储每个结束时间,所对应的工资,根据输入,每个结束时间可能会对应不同的工作和工资
int n, m, dp[N]; //dp[i]用来存储第i天挣得最多的钱
int x, y, z, T;
int main()
{
scanf("%d", &T);
while ( T-- ) {
scanf("%d%d", &n, &m);
for ( int i = 0; i <= n; ++i ) {
s[i].clear();
c[i].clear();
dp[i] = 0; //初始化为0
}
for ( int i = 0; i < m; ++i ) {
scanf("%d%d%d", &x, &y, &z);
if ( x > y ) continue;
if ( x < 1 ) continue;
if ( x > n || y > n ) continue;
s[y].push_back(x);
c[y].push_back(z);
}
for ( int i = 1; i <= n; ++i ) {
dp[i] = dp[i-1]; //将dp[i] 复制为dp[i-1] ,这一步不能省,因为如果第i天不是任何的工作的截止日期,那么它能赚的钱数就没有变,等于dp[i-1]i, 并且s[i]是空的不会进入接下来的循环
for( int j = 0; j < s[i].size(); ++j )
dp[i] = max( dp[i], dp[s[i][j]-1]+c[i][j] ); //如果i是某一个工作的结束日期,那么就要比较选择这个工作和不选择这个工作那个赚的比较多;然后一定是d[i]来比较,而不是d[i-1],这个要注意,在每一次循环后,dp[i]的值都可能改变;后面的是如果选择了这一天,那么赚的钱就是做这个工作的前一天的总工资加这个工作的工资
//printf("%d %d\n", i, dp[i]);
}
printf("%d\n", dp[n]);
}
}