树形动态规划

 

树形动态规划

分类: 算法   494人阅读  评论(0)  收藏  举报
tree apple output input struct 算法

Description
有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)
这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。
我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树
2 5
\ /
3 4
\ /
1
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。

Input
第1行2个数,N和Q(1 <= Q <= N,1 < N <= 100)。
N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。
每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。
每根树枝上的苹果不超过30000个。

Output
一个数,最多能留住的苹果的数量。

Sample Input
5 2
1 3 1
1 4 10
2 3 20
3 5 20

Sample Output
21


分析:

这题的权值在边上,这在思考时有些别扭,其实只要把边的权值转移到儿子结点上,问题性质不变。
这样状态就应该容易想到了,f[i][j]表示以i结点为根的子树保留j个结点所得的最大值。因为根结点没有权值,所以我们要保留p+1个点。
f[i][j]=max{f[i_left][k]+f[i_right][j-1-k]}   (0<=k<=j-1)
边界 f[i][0]=0;f[i][1]=value[i]
最后f[1][p+1]就是答案


为什么是j-1-k,而不是j-k呢?这是因为要保留以i为根的j个节点,而i已经占了一个节点了,所以孩子节点只能再保留j-1个节点了。

[cpp]  view plain copy
  1. #include<cstring>  
  2. #include<cstdio>  
  3. #include<iostream>  
  4. using namespace std;  
  5.   
  6. struct node  
  7. {  
  8.     int lc,rc;  
  9.     int s;  
  10. } tree[220];  
  11. int F[110][110],apple[110][110];  
  12. bool vis[110];  
  13. int n,q;  
  14. void make_tree(int root)//一旦涉及到树的操作,递归总是会简化很多代码  
  15. {//建立一颗二叉树  
  16.     vis[root]=true;  
  17.     for (int i=1;i<=n;i++)  
  18.         if (!vis[i] && apple[root][i]!=-1)  
  19.         {  
  20.             if (tree[root].lc==0) tree[root].lc=i;  
  21.             else tree[root].rc=i;  
  22.             tree[i].s=apple[root][i];  
  23.             make_tree(i);  
  24.         }  
  25. }  
  26. int tree_dp(int t,int k)  
  27. {  
  28.     if (F[t][k]!=-1) return F[t][k];  
  29.     if (t==0 || k==0)  
  30.     {  
  31.         F[t][k]=0; return 0;  
  32.     }  
  33.     F[t][k]=0;  
  34.     for (int i=0;i<=k-1;i++)  
  35.     {//递归左右孩子相加即为父亲最优值  
  36.         int ls=tree_dp(tree[t].lc,i);  
  37.         int rs=tree_dp(tree[t].rc,k-1-i);  
  38.         if (F[t][k]<ls+rs) F[t][k]=ls+rs;  
  39.     }  
  40.     F[t][k]+=tree[t].s;  
  41.     return F[t][k];  
  42. }  
  43. int main()  
  44. {  
  45.     scanf("%d%d",&n,&q); q++;  
  46.     memset(apple,-1,sizeof(apple));  
  47.     int a,b,s;  
  48.     for (int i=1;i<=n-1;i++)  
  49.     {  
  50.         scanf("%d%d%d",&a,&b,&s);  
  51.         apple[a][b]=s; apple[b][a]=s;  
  52.     }  
  53.     memset(tree,0,sizeof(tree));  
  54.     memset(vis,false,sizeof(vis));  
  55.     make_tree(1);  
  56.     memset(F,-1,sizeof(F));  
  57.     int ans=tree_dp(1,q);  
  58.     printf("%d\n",ans);  
  59.     return 0;  
  60. }  


在建树的时候也可以和图算法类似:

[cpp]  view plain copy
  1. #include <iostream>  
  2. #include <vector>  
  3. using namespace std;  
  4. const int maxn=110;  
  5. int  N, Q;  
  6. int  u, v, w;  
  7. int  dp[maxn][maxn];  
  8. struct Node  
  9. {  
  10.     int u, w;  
  11. };  
  12. vector<Node>adj[maxn];  
  13. void init( )  
  14. {  
  15.     for (int i=1; i<=N; i++) adj[i].clear();  
  16.     for (int i=1; i<N; i++)  
  17.     {  
  18.         scanf("%d%d%d", &u, &v, &w);  
  19.         Node temp;  
  20.         temp.u = v; temp.w = w;  
  21.         adj[u].push_back(temp);  
  22.         temp.u = u;  
  23.         adj[v].push_back(temp);  
  24.     }  
  25. }  
  26. void  dfs(int root, int father, int left)  
  27. {  
  28.     if (left<=0) return;  
  29.     for (int i=1; i<=Q; i++) dp[root][i] = 0;  
  30.     for (int i=0; i<adj[root].size(); i++)  
  31.     {  
  32.         int u=adj[root][i].u, w=adj[root][i].w;  
  33.         if (u!=father && left)  
  34.         {  
  35.              dfs(u, root, left-1);  
  36.              for (int j=left; j>=0; j--)  
  37.              {  
  38.                  for (int k=0; k+j+1<=left; k++)  
  39.                  {  
  40.                      dp[root][k+j+1] = max(dp[root][k+j+1], dp[u][k]+dp[root][j]+w);  
  41.                  }  
  42.              }  
  43.         }  
  44.     }  
  45.     if (left==1) return;  
  46. }  
  47. int  main( )  
  48. {  
  49.     while (cin>>N>>Q)  
  50.     {  
  51.         init( );  
  52.         dfs(1, 1, Q); //root is 1  
  53.         printf("%d\n", dp[1][Q]);  
  54.     }  
  55.     return 0;  
  56. }  

你可能感兴趣的:(算法)