dp例题01. 任务价值最大化
题目Description:
大凯有n项任务可选择去做, 分别对应有开始时间, 结束时间以及任务报酬, 同一时间内最多做一件任务, 现在大凯想知道最多能得到多少报酬, 于是把求解任务交给了你。
输入:第一行 为 n ——表示总共有n项任务 (n <= 5000)
接下来n行, 每行有三个数, 分别对应第i个任务的开始时间si, 结束时间ei 以及任务报酬vi。(0 <= si < ei <1e5, 0 < vi <= 1e5)
输出:最多能获得的报酬。
Sample Input:
8
0 6 8
3 5 1
8 11 4
6 10 2
1 4 5
4 7 4
3 8 6
5 9 3
Sample Output
13
解题思路: dp算法
先按任务结束时间进行升序排序。
dp[i] 表示做前面 i 个 任务所能得到的最多报酬。
这里构造一个pre数组, pre[i] 表示与做第i个任务不冲突的在i之前 又与之最近的任务
dp[i]的确定:做第i个任务还是不做? 比较dp[i-1] (不做第i个) 与 dp[pre[i]] + i对应的报酬, 即: dp[i] = (dp[i-1] > dp[prev[i]] + task[i].value)? dp[i-1] : dp[prev[i]] + task[i].value;
以下为c语言代码:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #define maxn 5005
4
5 struct e {
6 int start, end, value;
7 }task[maxn];
8
9 // 手写快排算法
10 void quick_sort(struct e * task, int left, int right) {
11 if (left >= right) return;
12 int l = left, r = right;
13 int base = rand() % (r - l + 1) + l;
14 struct e temp = task[base];
15 task[base] = task[l];
16 task[l] = temp;
17 base = task[l].end;
18 while (l < r) {
19 while (task[r].end > base && l < r) r--;
20 if (l < r) {
21 task[l] = task[r];
22 l++;
23 }
24 while (task[l].end <= base && l < r) l++;
25 if (l < r) {
26 task[r] = task[l];
27 r--;
28 }
29 }
30 task[l] = temp;
31 quick_sort(task, left, l-1);
32 quick_sort(task, l+1, right);
33 }
34
35 int main() {
36 int dp[maxn], prev[maxn], n;
37 scanf("%d", &n);
38 // 1到n记录, 空出0
39 for (int i = 1; i <= n; i++) {
40 scanf("%d%d%d", &task[i].start, &task[i].end, &task[i].value);
41 }
42
43 // 根据结束时间升序排序
44 quick_sort(task, 1, n);
45
46 // 构造prev数组 pre[i] 表示与做第i个任务不冲突的在i之前 又与之最近的任务
47 for (int i = 1; i <= n; i++) {
48 for (int j = i-1; j >= 0; j--) {
49 if (task[j].end <= task[i].start) {
50 prev[i] = j;
51 break;
52 }
53 }
54 }
55
56 // 有些任务不存在pre[i], 即pre[i] = 0, 前0个任务最多价值自然为0
57 dp[0] = 0;
58
59 for (int i = 1; i <= n; i++) {
60 dp[i] = (dp[i-1] > dp[prev[i]] + task[i].value)? dp[i-1] : dp[prev[i]] + task[i].value;
61 }
62 printf("%d\n", dp[n]);
63 return 0;
64 }
浙公网安备 33010602011771号