HDU 4003 [树][贪心][背包]
Posted 徐暾
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",ans); } }
以上是关于HDU 4003 [树][贪心][背包]的主要内容,如果未能解决你的问题,请参考以下文章
HDU-4003 Find Metal Mineral (树形DP+分组背包)