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\n",max(dp[0].second,dp[0].first)); 43 return 0; 44 }