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;
}
posted @ 2013-02-21 18:02  kedebug  阅读(315)  评论(0编辑  收藏  举报