HDU 4003 Find Metal Mineral

/*
题目大意:给你一颗树,你有K个机器人,每条有一定的权值,问用K个机器人访问所有节点所需的权值和最少是多少。
典型的树dp问题
设状态dp[i][j]表示到达节点i,用j个机器人访问其本身及其所有子节点所需要的最少代价
状态转移方程:
if (j == 0) dp[i][0] = dp[All i->son][0] + 2 * edge_cost(i, i->son);
if (j != 0)
则像背包问题类似的转移
dp[i][j] = min(dp[i->son][t] + dp[i][j-t] + t * edge_cost(i, i->son))

最后求得dp[s][k]即为答案
*/
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define Maxn 10050
using namespace std;

typedef pair<int,long long> pii;
vector<pii> edge[Maxn];

int n, s;
long long dp[Maxn][15], k;
void init()
{
     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].pb(mp(b, c));
         edge[b].pb(mp(a, c));         
     }
     memset(dp, -1, sizeof(dp));
     }
void dfs(int root, int fa)
{
     for (int i=0; i<edge[root].size(); i++)
       if (edge[root][i].fi != fa) dfs(edge[root][i].fi, 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].fi;
         long long w = edge[root][i].se;
         if (v == fa) continue;
         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)
    {
          init();
          dfs(s, -1);
          printf("%I64d\n", dp[s][k]);
    }
    return 0;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值