1. 程式人生 > >有線電視網【P1273】【樹形DP】

有線電視網【P1273】【樹形DP】

題目連結

    一道樹形DP,但是它的想法還是可以稱之為樹形揹包,依舊是從大數往下推,我的這一道題中有對樹形揹包的完整講解,這裡呢,就是DP的列寫得怎麼樣列寫?dp[i][j],以i號節點為根節點時,取j個人的時候,需要的代價,我們希望最後的代價為“>=0”的。

完整程式碼:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int maxN=3005;
int N, M;
int dp[maxN][maxN], val[maxN];
struct eddge
{
    int nex, val;
    eddge(int a=0, int b=0):nex(a), val(b) {}
};
vector<eddge> vt[maxN];
int dfs(int u)
{
    dp[u][0]=0;
    if(u>N-M) { dp[u][1]=val[u]; return 1; }
    int son=0, tmp=0, len=(int)vt[u].size();
    for(int i=0; i<len; i++)
    {
        int v=vt[u][i].nex, cost=vt[u][i].val;
        son+=(tmp=dfs(v));
        for(int j=son; j>=1; j--)
        {
            for(int k=1; k<=tmp; k++)
            {
                if(j>=k) dp[u][j]=max(dp[u][j], dp[u][j-k]+dp[v][k]-cost);
            }
        }
    }
    return son;
}
int main()
{
    scanf("%d%d", &N, &M);
        for(int i=1; i<=(N-M); i++)
        {
            int e1, e2, e3;
            scanf("%d", &e1);
            while(e1--)
            {
                scanf("%d%d", &e2, &e3);
                vt[i].push_back(eddge(e2, e3));
            }
        }
        for(int i=(N-M+1); i<=N; i++) scanf("%d", &val[i]);
    for(int i=1; i<=N; i++) for(int j=1; j<=N; j++) dp[i][j]=-1000000;
        dfs(1);
        for(int i=M; i>=0; i--)
        {
            if(dp[1][i]>=0)
            {
                printf("%d\n", i);
                break;
            }
            else if(i==0)
            {
                printf("0\n");
                break;
            }
        }
    return 0;
}