動態規劃-樹形DP-樹上背包專題
阿新 • • 發佈:2018-02-24
ace 整數 return urn edge 最大 沒有 != 格式
先看道題:選課
題目描述
在大學裏每個學生,為了達到一定的學分,必須從很多課程裏選擇一些課程來學習,在課程裏有些課程必須在某些課程之前學習,如高等數學總是在其它課程之前學習。
現在有N門功課,每門課有個學分,每門課有一門或沒有直接先修課(若課程a是課程b的先修課即只有學完了課程a,才能學習課程b)。一個學生要從這些課程裏選擇M門課程學習,問他能獲得的最大學分是多少?
輸入輸出格式
輸入格式:
第一行有兩個整數N,M用空格隔開。(1<=N<=300,1<=M<=300)
接下來的N行,第I+1行包含兩個整數ki和si, ki表示第I門課的直接先修課,si表示第I門課的學分。若ki=0表示沒有直接先修課(1<=ki<=N, 1<=si<=20)。
輸出格式:
只有一行,選M門課程的最大得分。
輸入輸出樣例
輸入樣例#1:
7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2
輸出樣例#1:
13
通俗點講呢呢就是類似於點一個技能樹(霧),點亮每個技能點上都能獲得一定經驗值,但你的天賦值是有限的(M),問你怎麽點使得收獲的經驗值最大。
如果每個節點上收獲到的收益是相等的,顯然我們能用貪心的方法。
但是這時每個節點上的收益是不同的,所以我們就需要動態規劃。
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int maxn=310; int n,m; int c[maxn]; int h[maxn],num_edge=0; int f[maxn][maxn]; bool vis[maxn]; struct Node { int ne,to; }edge[maxn]; void add_edge(int f,int to) { edge[++num_edge].ne=h[f]; edge[num_edge].to=to; h[f]=num_edge; } void dfs(int x,int pre) { int i; if(vis[x])return ; vis[x]=1; f[x][1]=c[x]; for(i=h[x];i!=0;i=edge[i].ne) { int s=edge[i].to; dfs(s,x); for(int j=m;j>=0;j--) for(int k=0;k<j;k++) f[x][j]=max(f[x][j],f[s][k]+f[x][j-k]); } } int main() { cin>>n>>m; m++; for(int i=1;i<=n;i++) { int ki; cin>>ki>>c[i]; add_edge(ki,i); } dfs(0,-1); cout<<f[0][m]<<endl; return 0; }
動態規劃-樹形DP-樹上背包專題