Luogu2015 二叉蘋果樹
阿新 • • 發佈:2018-12-09
題目描述
有一棵蘋果樹,如果樹枝有分叉,一定是分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個。
輸出格式:
一個數,最多能留住的蘋果的數量。
保留Q條邊,即保留Q+1個結點。
我們記f[i][j]為以i為根的子樹中,保留j個結點最多留住蘋果的數量。
這樣這個點的每個子樹都可以不選,或選1~j-1個結點,另一個子樹放剩下的點。
記a[i]為i到它父親的邊上蘋果的數量。
則狀態轉移顯然:f[i][j]=max(f[i][j],f[lc[i]][k]+f[rc[i]][j-k-1]+a[i]) k從0到j。lc和rc分別表示該點的左兒子和右兒子
程式碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #define maxn 200 using namespace std; int lc[maxn],rc[maxn],f[maxn][maxn],map[maxn][maxn],a[maxn],n,q; void build(int now) { for(int i=1;i<=n;i++){ if(map[now][i]>=0){ lc[now]=i; a[i]=map[now][i]; map[now][i]=-1; map[i][now]=-1; build(i); break; } } for(int i=1;i<=n;i++){ if(map[now][i]>=0){ rc[now]=i; a[i]=map[now][i]; map[now][i]=map[i][now]=-1; build(i); break; } } } int dfs(int i,int j) { if(j==0) return 0; if(!lc[i]&&!rc[i]) return a[i]; if(f[i][j]) return f[i][j]; for(int k=0;k<=j-1;k++) f[i][j]=max(f[i][j],dfs(lc[i],k)+dfs(rc[i],j-k-1)+a[i]); return f[i][j]; } int main() { cin>>n>>q; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ map[i][j]=-1; } } for(int i=1;i<n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); map[x][y]=z,map[y][x]=z; } build(1); cout<<dfs(1,q+1); return 0; }