[关闭]
@Seymour 2018-08-08T19:39:54.000000Z 字数 1577 阅读 969

树形DP

算法


树形DP

二叉苹果树(ural 1108)

题目意思:

有一棵苹果树,苹果树的是一棵二叉树,共N个节点,树节点编号为1~N,编号为1的节点为树根,边可理解为树的分枝,每个分支都长着若干个苹果,现在要要求减去若干个分支,保留M个分支,要求这M个分支的苹果数量最多。

输入:

N M

接下来的N-1行是树的边,和该边的苹果数N and M (1 ≤ M < N; 1 < N ≤ 100)

输出:

剩余苹果的最大数量。

input

5 2

1 3 1

1 4 10

2 3 20

3 5 20

output

21

算法:

删除了某个分支,那么这个分支下的子分支也同时删除。

保留M个分支,也就是删除N-M-1个分支。剩余的最多苹果数=总苹果数-剪掉的苹果数。

注意本题给的边并没有按照树根--树叶的形式来给,也没有按照树的顺序给出边。本来想一个节点对应一个分支长着的苹果数量,cost[v]就表示v这个节点的苹果数,可以这样做,但是在输入的时候,不知道这个苹果数量是那个节点的,因为不知道哪个是哪个的子结点。所以用了无向图和苹果数加到边上去。

我的解法中:这题的树状DP的整体思想个pku3345是一样的。

有一些不一样的地方要注意一下:

本程序其实不仅仅针对二叉树,可以是任意的树,删除任意个分支都有算。

  1. #include<iostream>
  2. #include<vector>
  3. #include<limits>
  4. using namespace std;
  5. #define MN 110
  6. int f[2*MN],p[MN],tmp[MN];
  7. int N,M;
  8. bool visit[MN];
  9. struct NODE
  10. {
  11. int val;
  12. int cost;
  13. };
  14. vector<NODE>G[MN];
  15. inline int max(int a,int b)
  16. {
  17. return a>b?a:b;
  18. }
  19. inline int min(int a,int b)
  20. {
  21. return a<b?a:b;
  22. }
  23. void my_clear()
  24. {
  25. int i;
  26. for(i=0;i<=N;i++)
  27. {
  28. G[i].clear();
  29. }
  30. memset(visit,false,sizeof(visit));
  31. }
  32. int DP(int v,int from)
  33. {
  34. visit[v]=true;
  35. int i,j,k,s,w,last,now;
  36. s=G[v].size();
  37. if(s==1) //这边不再是s==0
  38. {
  39. p[0]=0;
  40. return 1;
  41. }
  42. last=0;
  43. f[from]=0;
  44. for(i=0;i<s;i++)
  45. {
  46. w=G[v][i].val;
  47. if(visit[w]==true)
  48. continue;
  49. now=DP(w,from+last+1);
  50. p[now]=p[now-1]+G[v][i].cost; //这边不要漏,把节点w也给删除
  51. for(j=0;j<=last+now;j++)
  52. tmp[j]=INT_MAX;
  53. for(j=0;j<=last;j++)
  54. {
  55. for(k=0;k<=now;k++)
  56. {
  57. tmp[j+k]=min(tmp[j+k],f[from+j]+p[k]);
  58. }
  59. }
  60. last+=now;
  61. for(j=0;j<=last;j++)
  62. {
  63. f[from+j]=tmp[j];
  64. }
  65. }
  66. for(i=0;i<=last;i++)
  67. p[i]=f[i+from];
  68. last++; //加上自身节点
  69. return last;
  70. }
  71. int main()
  72. {
  73. int i,a,b,sum,c;
  74. NODE tmp;
  75. while(scanf("%d%d",&N,&M)!=EOF)
  76. {
  77. sum=0;
  78. my_clear();
  79. for(i=1;i<N;i++)
  80. {
  81. scanf("%d%d%d",&a,&b,&c);
  82. tmp.cost=c;
  83. tmp.val=b;
  84. G[a].push_back(tmp);
  85. tmp.val=a;
  86. G[b].push_back(tmp);
  87. sum+=c;
  88. }
  89. DP(1,0);
  90. printf("%d\n",sum-f[N-M-1]);
  91. }
  92. return 0;
  93. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注