来源:http://acm.hdu.edu.cn/showproblem.php?pid=4003
题意:给定k个机器人去遍历n个节点的树,求最小花费
分析:dp[root][j]表示以root为根时,用j个机器人走完所花费的最小价值。
状态转移方程:
当j==0时,dp[i][0]=dp[son][0]+2*w son是i的所有子节点,w是i到son的花费;
当j!=0时,dp[i][0]=min(dp[son][t]+dp[i][j-t]+t*w)son是i的所有子节点,w是i到son的花费。
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#define Maxn 10050
using namespace std;
struct node
{
int x;
long long val;
node(int a,long long b):x(a),val(b) {};
};
vector<node> edge[Maxn];
int n,s;
long long dp[Maxn][15],k;
void dfs(int root,int fa)
{
for(int i=0;i<edge[root].size();i++)
{
if (edge[root][i].x != fa)
{
dfs(edge[root][i].x,root);
}
}
if((edge[root].size()==1&&fa!=-1)||(fa==-1&&edge[root].size()==0))
{
for(int i=0;i<=k;i++)
dp[root][i]=0;
return;
}
for(int i=0;i<edge[root].size();i++)
{
int v=edge[root][i].x;
long long w=edge[root][i].val;
if (v!=fa)
{
for(int j=k;j>=0;j--)
{
if(dp[root][j]==-1)
{
if(!j)
dp[root][j]=dp[v][j]+2 * w;
else
{
for(int t=1; t<=j; t++)
if(dp[root][j]==-1||dp[root][j]>dp[v][t]+t*w)
dp[root][j]=dp[v][t]+t*w;
}
continue;
}
else
dp[root][j]+=dp[v][0]+2*w;
for (int t=1;t<=j;t++)
{
dp[root][j]=min(dp[root][j],dp[root][j-t]+dp[v][t]+t*w);
}
}
}
}
}
int main()
{
while(scanf("%d%d%I64d",&n,&s,&k)!=EOF)
{
int a,b;
long long c;
for(int i=0;i<=n;i++)
edge[i].clear();
for(int i=1;i<n;i++)
{
scanf("%d%d%I64d",&a,&b,&c);
edge[a].push_back(node(b,c));
edge[b].push_back(node(a,c));
}
memset(dp,-1,sizeof(dp));
dfs(s,-1);
printf("%I64d\n",dp[s][k]);
}
return 0;
}