1. 程式人生 > >動態規劃-樹形DP-樹上背包專題

動態規劃-樹形DP-樹上背包專題

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-樹上背包專題