HDU 4003 [树][贪心][背包]

/*
大连热身A题
不要低头,不要放弃,不要气馁,不要慌张
题意:
给一棵树,每条边上有权值。给一个起点,放置n个机器人,要求使得任意一个节点至少被一个机器人经过。
每个机器人经过某条边时的代价为这条边的权值。反复经过需要反复累积。
问最小的代价是什么。


思路:
1.转化为背包问题。考虑给某个子树i个机器人的最小代价,即有i个机器人跑到某棵子树不回来。其中0个代表给某子树一个机器人,该机器人
遍历完该子树所有节点以后又返回该节点的代价。然后相当于每棵子树有几个物品,至少从中选择一个。进行分组背包。
2.为什么以上转化是成立的,即是否有可能把某个机器人指派到某棵子树以后,该机器人又跑到其它子树,最后停留在其它子树,而能使得花
费的代价更优。事实是不可能的,因为如果该节点跑到子树的某个叶子节点又返回母亲节点,代价肯定比一开始就指派给该子树的机器人,让
它先走到那个节点所经过的叶子节点,再回到子树的根花费的代价要大。所以可以将这个问题转化为分组背包。


*/
#include<bits/stdc++.h>
#define N 10060
using namespace std;
long long dp[N][2][15];
int k;
int fa[N];
long long inf=0x3f3f3f3f3f3f3f3f;
struct edge{
    int id;
    long long w;
    edge *next;
};
int ednum;
edge *adj[N];
edge edges[N<<1];
inline void addedge(int a,int b,long long w){
    edge *tmp=&edges[ednum++];
    tmp->id=b;
    tmp->w=w;
    tmp->next=adj[a];
    adj[a]=tmp;
}
void dfs(int pos){
    bool ok=0;
    for(edge *it=adj[pos];it;it=it->next){
        if(!fa[it->id]){
            ok=1;
            fa[it->id]=pos;
            dfs(it->id);
            dp[pos][0][0]+=dp[it->id][0][0]+2*it->w;
        }
    }
    if(ok){
        for(int i=1;i<=k;i++)dp[pos][0][i]=inf;
        for(edge *it=adj[pos];it;it=it->next){
            memset(dp[pos][1],0x3f,sizeof(dp[pos][1]));
            if(fa[it->id]==pos){
                for(int i=1;i<=k;i++){
                    for(int j=i;j<=k;j++){
                        if(dp[pos][0][j-i]!=inf)
                            dp[pos][1][j]=min(dp[pos][0][j-i]-dp[it->id][0][0]+(i-2)*it->w+dp[it->id][0][i],dp[pos][1][j]);
                    }
                }
                for(int i=1;i<=k;i++)dp[pos][0][i]=min(dp[pos][0][i],dp[pos][1][i]);
            }
        }
    }
}
int main()
{
    int n,s;
    while(scanf("%d%d%d",&n,&s,&k)!=EOF){
        memset(adj,NULL,sizeof(adj));
        ednum=0;
        for(int i=1;i<n;i++){
            int a,b;
            long long w;
            scanf("%d%d%lld",&a,&b,&w);
            addedge(a,b,w);
            addedge(b,a,w);
        }
        memset(fa,0,sizeof(fa));
        fa[s]=s;
        memset(dp,0,sizeof(dp));
        dfs(s);
        long long ans=inf;
        for(int i=0;i<=k;i++)ans=min(ans,dp[s][0][i]);
        printf("%lld
",ans);
    }
}
原文地址:https://www.cnblogs.com/tun117/p/6001973.html