luogu P2015 二叉苹果树

一道qq姐和dtx很早就做了的题www

想学树形dp就是从这道题开始的

然后做了几道题

之后被难住了

于是回来做这道题

首先这道题保证了是一棵二叉树

emmmmm

然后一个dp数组

dp[u][j] 代表保留u节点j条边的最大值

题目保证1为根,那么结果就是dp[1][Q]

状态转移方程:

dp[u][j] = max(dp[u][j],dp[u][j - k - 1] + dp[v][k] + edge[i].weight)

v为u的子节点,k是枚举v保留的边的数

保留j条边的话,其中有一条边是u和v所连的边

所以保留v节点k条边再加上u节点剩下的可以保留的j - 1 - k条边再加上u和v之间的边

状态转移方程真的太难想了www

看看代码吧

#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 110

struct EDGE{
  int nxt,to,weight;
}edge[maxn * 2];//因为忘了开二倍所以emmm

int head[maxn],cnt;
int dp[maxn][maxn];
int n,q;

void add(int x,int y,int w){
  edge[++cnt].nxt = head[x];
  edge[cnt].to = y;
  head[x] = cnt;
  edge[cnt].weight = w;
}

int treedp(int u,int fa){
  int num = 0;
  for(int i = head[u];i;i = edge[i].nxt){
    int v = edge[i].to;
    if(v != fa){//存的双向所以防止死循环
      num += treedp(v,u) + 1;//return一个值,子树的边数,再加上相连的一条
      for(int j = min(num,q);j > 0;j--)
    for(int k = min(num,j);k >= 0;k--)
      dp[u][j] = max(dp[u][j],dp[u][j - k - 1] + dp[v][k] + edge[i].weight);
    }
  }
  return num;
}

int main(){
  scanf("%d%d",&n,&q);
  for(int i = 1;i < n;i++){
    int x,y,w;
    scanf("%d%d%d",&x,&y,&w);
    add(x,y,w);
    add(y,x,w);
  }
  treedp(1,0);
  printf("%d",dp[1][q]);
  return 0;
}

【令人头大

 

/*

然后最后插一句没什么意义的感慨

我们都是

      渺小而平庸的

            无名之辈

谢谢你们能在这么短暂的生命之中,记住我的名字

 (没错就是看完电影哭的不行之后的伤春悲秋www

*/ 

 

posted @ 2019-01-12 19:04  ./seven  阅读(96)  评论(0编辑  收藏  举报