「Luogu P2015」二叉蘋果樹 解題報告
阿新 • • 發佈:2019-01-05
題面
一個二叉樹,邊數為n\((2<n\le 100)\),每條邊有一個權值,求剪枝後剩下p\((1<p<n)\)條邊,使p條邊的權值和最大
還看不懂?……
2 5 input:5 2 output:21
\ / 1 3 1
3 4 1 4 10
\ / 2 3 20
1 3 5 20
能理解了吧!
思路:
樹形打屁DP
很基礎的一道樹形DP
對於每個點,用f[k][i]
記錄在以k
為根的子樹中,取i
條枝的最大值
注意:
1、要注意葉子節點的判斷
2、有可能只取一側的子樹
Code:
#include<bits/stdc++.h> #define N 110 using namespace std; int b[N][5],s[N]; int n,p; int a[N][N],f[N][N]; int read() { int s=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { s=(s<<1)+(s<<3)+c-'0'; c=getchar(); } return s; } void DFS(int k,int fa) { if(s[k]==1)//葉子節點直接返回 return; int i,j; int l,r,value; l=r=0; for(i=1;i<=s[k];i++)//把l兒子和r兒子處理出來,其實不用嚴格區分l和r,因為效果是一樣的 if(b[k][i]!=fa) { if(!l) l=b[k][i]; else r=b[k][i]; } DFS(l,k);DFS(r,k); f[k][1]=max(a[k][l],a[k][r]);// for(i=0;i<=p-2;i++)//由於預設要選左枝和右枝,所以i要-2 { f[k][i+2]=max(f[l][i+1]+a[k][l],f[r][i+1]+a[k][r]);//可能直選一邊 for(j=0;j<=i;j++)//分配左子樹多少,右子樹去多少枝,不用判斷是否能夠取滿,因為取滿的總是最優的 {//不會影響 value=f[l][j]+a[k][l]+f[r][i-j]+a[k][r]; f[k][i+2]=max(f[k][i+2],value); } } return; } int main() { int i,x,y; n=read();p=read(); for(i=1;i<n;i++) { x=read(),y=read(),a[x][y]=read();//矩陣存邊權 b[x][++s[x]]=y;b[y][++s[y]]=x;//存邊,由於邊數不多,直接用鄰接表存,不用鏈式前向星 } DFS(1,0);//以1為根遍歷數 printf("%d",f[1][p]);//輸出最後結果 return 0; }