洛谷P2014 选课 #树形DP 依赖背包#

题目描述

在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有 NN 门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b)。一个学生要从这些课程里选择 MM 门课程学习,问他能获得的最大学分是多少?

输入格式

第一行有两个整数 NN , MM 用空格隔开。( 1 \leq N \leq 3001≤N≤300 , 1 \leq M \leq 3001≤M≤300 )

接下来的 NN 行,第 I+1I+1 行包含两个整数 k_iki​和 s_isi​, k_iki​ 表示第I门课的直接先修课,s_isi​ 表示第I门课的学分。若 k_i=0ki​=0 表示没有直接先修课(1 \leq {k_i} \leq N1≤ki​≤N , 1 \leq {s_i} \leq 201≤si​≤20)。

输出格式

只有一行,选 MM 门课程的最大得分。

输入输出样例

输入 #1复制

7  4
2  2
0  1
0  4
2  1
7  1
7  6
2  2

输出 #1复制

13

题解

虚拟出一个编号为0的课程为祖先,故预处理总课程数+1。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 3e2 + 10;
int n, m, cnt, h[maxn], s[maxn], dp[maxn][maxn];
struct edge { int to, next; } e[maxn];

inline const int read()
{
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); }
    return x * f;
}

void addEdge(int u, int v)
{
    e[cnt].to = v;
    e[cnt].next = h[u];
    h[u] = cnt++;
}

void dfs(int u)
{
    for (int i = h[u]; ~i; i = e[i].next)
    {
        int v = e[i].to;
        dfs(v);
        for (int j = m - 1; j >= 0; j--)
            for (int k = 0; k <= j; k++)
                dp[u][j] = max(dp[u][j], dp[u][j - k] + dp[v][k]);
    }
    for (int i = m; i > 0; i--) dp[u][i] = dp[u][i - 1] + s[u];
//    dp[u][0] = 0;
}

int main()
{
    memset(h, -1, sizeof(h));
    n = read(); m = read() + 1;
    for (int i = 1; i <= n; i++)
    {
        addEdge(read(), i);
        s[i] = read();
    }
    dfs(0);
    printf("%d\n", dp[0][m]);
    return 0;
}
发布了367 篇原创文章 · 获赞 148 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_35850147/article/details/103980422
今日推荐