HDOJ 4003 Find Metal Mineral(树形DP)

题意:

一棵有权树,从根结点中放入 K 个机器人,求用这 K 个机器人遍历所有的结点最少的权值和。

思路:

1. dp[u][i] 表示给以 u 为根节点的子树放 i 个机器人,遍历其子树所需要的最小权值。

2. 关键在于 dp[u][0] 的理解,表示:最后停留在以 u 为根节点的子树下 0 个机器人,并且遍历了 u 子树的最小权值和。

3. 下面的步骤就变成和分组背包类似的情况了,根节点 u 给孩子 v 放多少个机器人。

4. dp[u][i] = min(dp[u][i], dp[u][j] + dp[v][i-j] + (i-j) * c); 可以理解成给 v 放了 i-j 个机器人,给 v 的其他兄弟放了 j 个,u 总共有 i 个

 

#include <iostream>

#include <algorithm>

using namespace std;



const int MAXN = 10010;

const int MAXD = 11;



struct edge {

    int v, c;

    edge* next;

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



int EC, N, S, K, dp[MAXN][MAXD];

bool vis[MAXN];



void addedge(int u, int v, int c)

{

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

    V[u] = ES + EC; 

    V[u]->v = v, V[u]->c = c;

}



void initdata()

{

    EC = 0;

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

    memset(vis, false, sizeof(vis));



    for (int i = 0; i < N - 1; ++i)

    {

        int x, y, w;

        scanf("%d %d %d", &x, &y, &w);

        addedge(x, y, w);

        addedge(y, x, w);

    }

}



void treedp(int u)

{

    vis[u] = true;

    memset(dp[u], 0, sizeof(dp[0]));



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

    {

        int v = e->v, c = e->c;



        if (vis[v])

            continue ;



        treedp(v);



        for (int i = K; i >= 0; --i)

        {

            dp[u][i] += dp[v][0] + 2 * c;

            for (int j = 0; j <= i; ++j)

                dp[u][i] = min(dp[u][i], dp[u][j] + dp[v][i-j] + (i-j) * c);

        }

    }

}



int main()

{

    while (scanf("%d %d %d", &N, &S, &K) != EOF)

    {

        initdata();

        treedp(S);

        printf("%d\n", dp[S][K]);

    }

    return 0;

}

你可能感兴趣的:(find)