1. 程式人生 > >Luogu P2014 選課 (樹形DP)

Luogu P2014 選課 (樹形DP)

clas struct knapsack 一定的 code 獲得 bit esp aps

題目

題目描述

在大學裏每個學生,為了達到一定的學分,必須從很多課程裏選擇一些課程來學習,在課程裏有些課程必須在某些課程之前學習,如高等數學總是在其它課程之前學習。現在有N門功課,每門課有個學分,每門課有一門或沒有直接先修課(若課程a是課程b的先修課即只有學完了課程a,才能學習課程b)。一個學生要從這些課程裏選擇M門課程學習,問他能獲得的最大學分是多少?

輸入輸出格式

輸入格式:

第一行有兩個整數N,M用空格隔開。(1<=N<=300,1<=M<=300)

接下來的N行,第i+1行包含兩個整數kisi, ki表示第i門課的直接先修課,si表示第i門課的學分。若ki=0表示沒有直接先修課(1<=ki<=N

, 1<=si<=20)。

輸出格式:

只有一行,選M門課程的最大得分。

輸入輸出樣例

輸入樣例:
7  4
2  2
0  1
0  4
2  1
7  1
7  6
2  2
輸出樣例:
13

題解

又是一道經典的樹形DP,和二叉蘋果樹很像,不過用到了背包(Knapsack)的思想

dp[i][j]表示i課程下選擇j門課程得到的最大學分

代碼

#include <bits/stdc++.h>
using namespace std;
struct node {
  int credit, father;
  vector<int> attached;
} tree[310];
int n, m;
int dp[310][310];
inline int Dfs(const int &now) {
  if (!tree[now].attached.size()) return 0;
  register int sum(0);
  for (register int i(0), 
                    t_size(tree[now].attached.size()), tmp; i < t_size; ++i) {
    sum += tmp = Dfs(tree[now].attached[i]);
    for (register int j(++sum); j; --j) {
      for (register int k(0); k <= tmp; ++k) {
        if (j - k - 1 >= 0) dp[now][j] = max(dp[now][j], 
                                             dp[now][j - k - 1] + 
                                             dp[tree[now].attached[i]][k]);
      }
    }
  }
  return sum;
}
int main(int argc, char **argv) {
  scanf("%d %d", &n, &m);
  for (register int i(1), attached_to, credit; i <= n; ++i) {
    scanf("%d %d", &attached_to, &credit);
    tree[attached_to].attached.push_back(i);
    tree[i].father = attached_to;
    tree[i].credit = dp[i][0] = credit;
  }
  Dfs(0);
  printf("%d\n", dp[0][m]);
  return 0;
}

Luogu P2014 選課 (樹形DP)