hdu 4003 Find Metal Mineral(树形DP)
题意:给定一棵树,每条边都有各自的权值,要求用K个机器人(从根出发),遍历整棵数,求最小总权值
分析:一开始很清楚的知道,还是一道树形背包,用dp[i][j]表示以节点i为根的子树选了j个机器人遍历的权值和。
关键在j==0 时的意义的理解,一开始总处理不好,就是dp[i][0]表示的是以i为根的子树放置一个机器人遍历完子树之后又回到i
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
using namespace std;
const int N = 10010;
int n,K,S;
__int64 dp[N][11];
bool vis[N];
struct edge
{
int v,w;
edge(){}
edge(int a,int b):v(a),w(b){}
};
vector<edge> g[N];
void init()
{
for(int i=0;i<=n;i++)
g[i].clear();
memset(dp,0,sizeof(dp));
memset(vis,false,sizeof(vis));
}
void dfs(int u)
{
int size=g[u].size();
if(size==0)
return ;
for(int i=0;i<size;i++)
{
int v=g[u][i].v;
if(vis[v]) continue;
vis[v]=true;
dfs(v);
for(int j=K;j>=0;j--)
{
dp[u][j]+=dp[v][0]+g[u][i].w*2;//v所在子树不放置机器人,这个要单独处理,同时也是因为,每一个分支都要遍历到
for(int k=1;k<=j;k++)//子树放置1~j个机器人
dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]+k*g[u][i].w);
}
}
}
int main()
{
int x,y,w;
while(scanf("%d %d %d",&n,&S,&K)==3)
{
init();
for(int i=1;i<n;i++)
{
scanf("%d %d %d",&x,&y,&w);
g[x].push_back(edge(y,w));
g[y].push_back(edge(x,w));
}
vis[S]=true;
dfs(S);
printf("%I64d\n",dp[S][K]);
}
return 0;
}