Helvetic Coding Contest 2017 online mirror K. Send the Fool Further! (medium)(树形DP)

题目链接:Helvetic Coding Contest 2017 online mirror K. Send the Fool Further! (medium)

题意:

给你一棵树,每条边有一个价值,现在每个节点最多访问k次,问最大的价值是多少。

每个价值只能加一次。

题解:

考虑dp[i][j(0||1)]表示以第i个节点为根的子树,最多访问i节点k次(0表示最后回到i节点,1表示不回到i节点)的最大价值。

状态转移方程为dp[i][0]=max{k-1个子节点的sum(dp[j][0])},dp[i][1]=max{k-1个子节点的sum(dp[j][0])+dp[l][1]}

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=(a);i<=(b);++i)
 3 using namespace std;
 4 typedef pair<int,int>P;
 5 
 6 const int N=1e5+7;
 7 int n,k,ed;
 8 P dp[N],tmp[N];
 9 vector<P>g[N];
10 
11 inline void up(int &a,int b){if(a<b)a=b;}
12 
13 bool cmp(const P &a,const P &b){return a.first!=b.first?a.first>b.first:a.second>b.second;}
14 
15 void dfs(int x=0,int fa=-1)
16 {
17     for(auto &it:g[x])if(it.first!=fa)dfs(it.first,x);
18     ed=0;
19     for(auto &it:g[x])if(it.first!=fa)tmp[++ed]=P(dp[it.first].first+it.second,dp[it.first].second+it.second);
20     if(!ed)return;
21     sort(tmp+1,tmp+1+ed,cmp);
22     for(int i=1;i<k&&i<=ed;i++)dp[x].first+=tmp[i].first;
23     int sum=0;
24     for(int i=1;i<=k&&i<=ed;i++)sum+=tmp[i].first;
25     F(i,1,ed)
26     {
27         if(i<=k)up(dp[x].second,sum+tmp[i].second-tmp[i].first);
28         else up(dp[x].second,sum+tmp[i].second-tmp[k].first);
29     }
30 }
31 
32 int main(){
33     scanf("%d%d",&n,&k);
34     F(i,1,n-1)
35     {
36         int x,y,z;
37         scanf("%d%d%d",&x,&y,&z);
38         g[x].push_back({y,z});
39         g[y].push_back({x,z});
40     }
41     dfs();
42     printf("%d
",max(dp[0].second,dp[0].first));
43     return 0;
44 }
View Code
原文地址:https://www.cnblogs.com/bin-gege/p/7151127.html