MZOJ 1134 && LuoGu P2015 二叉苹果树
MZOJ 1134 && LuoGu P2015 二叉苹果树 [传送门]
题目描述
有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)
这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。
我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树
2 5
\ /
3 4
\ /
1
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。
输入输出格式
输入格式:
第1行2个数,N和Q(1<=Q<= N,1<N<=100)。
N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。
每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。
每根树枝上的苹果不超过30000个。
输出格式:
一个数,最多能留住的苹果的数量。
输入输出样例
输入样例:
5 2
1 3 1
1 4 10
2 3 20
3 5 20
输出样例:
21
总的来说其实和选课也没什么不同,也是树形DP,也是有依赖关系(如果剪掉下面的枝条上面的苹果铁定要一起被剪掉);
所以直接上代码:
#include<bits/stdc++.h> using namespace std; const int maxn=500; int N,Q; int head[maxn],k=0; int w[maxn][maxn],f[maxn][maxn]; struct edge{ int v,w,nxt; }e[maxn<<1]; void init(){ freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); } void adde(int u,int v){ e[k].v=v; e[k].nxt=head[u]; head[u]=k++; } void readdata(){ int u,v,c; memset(head,-1,sizeof(head)); scanf("%d%d",&N,&Q); for(int i=1;i<N;i++){ scanf("%d%d%d",&u,&v,&c); adde(u,v); adde(v,u); w[u][v]=w[v][u]=c; } } int dp(int u,int fa){ f[u][0]=0;f[u][1]=w[u][fa]; int size=1; for(int i=head[u];~i;i=e[i].nxt){ int v=e[i].v; if (v==fa) continue; int s=dp(v,u); size+=s; for(int j=size;j>0;j--){ for(int k=0;k<j;k++){ if(k>s)continue; else f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]); } } } return size; } void work(){ dp(1,0); printf("%d",f[1][Q+1]); } int main(){ //init(); readdata(); work(); return 0; }