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;
}
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------