HDOJ 1011 Starship Troopers(树形DP)

题意:

给出一棵树,每个点有权值,要取得这个权值需要代价,通过父亲后才能到达儿子。问能量有限时获得的最大值

思路:

1. 树形DP,要特殊考虑 m = 0 的情况,

2. 注意你走过的所有叶子节点都必须留下一人,但是中间的节点可以不留人,即使叶子bugs为0.但是因为要收割possible,必须有 trooper

3. 用泛化背包优化了半天,无奈水平有限,一直WA,后来想想可能此题确实无法像论文中那样的有依赖背包的优化,因为 m = 0 这个奇葩的存在。

 调试半天虽然优化无果,但是也进一步加深了对于树形动态规划的理解,一些边边角角还是有待于打磨。

 

#include <iostream>

#include <algorithm>

using namespace std;



const int MAXN = 110;



struct edge {

    int v;

    edge* next;

} *V[MAXN], ES[MAXN * 2];



int EC, dp[MAXN][MAXN], B[MAXN], P[MAXN];



void addedge(int u, int v)

{

    ES[++EC].next = V[u];

    V[u] = ES + EC; V[u]->v = v;

}



void initdata(int n)

{

    for (int i = 1; i <= n; ++i)

    {

        scanf("%d %d", &B[i], &P[i]);

        B[i] = (B[i] + 19) / 20;

    }



    EC = 0;

    memset(V, 0, sizeof(V));



    for (int i = 1; i < n; ++i)

    {

        int a, b;

        scanf("%d %d", &a, &b);

        addedge(a, b);

        addedge(b, a);

    }

    memset(dp, 0, sizeof(dp));

}



void treedp(int u, int f, int vol)

{

    if (vol <= 0)

        return ;



    dp[u][B[u]] = P[u];



    for (edge* e = V[u]; e; e = e->next)

    {

        if (e->v == f)

            continue;



        treedp(e->v, u, vol - B[u]);



        for (int i = vol; i >= B[u]; --i)

            for (int j = 0; j <= i - B[u]; ++j)

                dp[u][i] = max(dp[u][i], dp[u][i-j] + dp[e->v][j]);

    }



    if (dp[u][0] > 0)

    {

        dp[u][1] = max(dp[u][0], dp[u][1]);

        dp[u][0] = 0;

    }

}



int main()

{

    int n, m;

    while (scanf("%d %d", &n, &m))

    {

        if (n == -1 && m == -1)

            break ;



        initdata(n);

        treedp(1, 0, m);



        printf("%d\n", dp[1][m]);

    }

    return 0;

}

你可能感兴趣的:(oop)