HDOJ 4003 Find Metal Mineral (树DP)
题意:给定一棵树,边权表示通过此边的代价,给k个机器人,指定从点s出发,求遍历所有结点的最小代价和。
分析:设计状态时不难想到用dp[i][j]表示从结点 i 出发遍历以它为根的子树的最小代价,但是转移时就遇到麻烦了,考虑只给你 1 个机器人的时候,这时要遍历所有结点就必然要走回头路,如果我们对每个结点再增加一个信息,表示从 i 出发遍历以 i 为根的子树且最后回到 i 的最小代价,这样转移就好办了,对于每个结点,将 j 个机器人分配给它的所有子结点,若分配 0 个机器人,则表明要派一个机器人去,遍历完了又回到 i 。方便起见,就以dp[i][0]表示从 i 出发遍历完子树 i 又回到i的最小代价。
View Code
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 10010 #define M 11 int n,e,s,m; int first[N],next[N<<1],v[N<<1],w[N<<1],d[N]; int dp[N][M]; void init() { e=0; memset(first,-1,sizeof(first)); memset(d,0,sizeof(d)); memset(dp,0,sizeof(dp)); } void add(int a,int b,int c) { d[a]++; v[e]=b; w[e]=c; next[e]=first[a]; first[a]=e++; } void dfs(int a,int fa) { if(d[a]==1 && v[first[a]]==fa) return; int i,j,k,b; for(i=first[a];~i;i=next[i]) { b=v[i]; if(b==fa) continue; dfs(b,a); for(j=m;j>=0;j--) { dp[a][j]+=dp[b][0]+2*w[i]; for(k=1;k<=j;k++) { dp[a][j]=min(dp[a][j],dp[a][j-k]+dp[b][k]+k*w[i]); } } } } int main() { int a,b,c; while(~scanf("%d%d%d",&n,&s,&m)) { init(); for(int i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } dfs(s,0); printf("%d\n",dp[s][m]); } return 0; }