1. 程式人生 > 其它 >loj10154 樹形dp(多叉樹轉二叉樹)

loj10154 樹形dp(多叉樹轉二叉樹)

好久沒有做關於樹dp的題,一做就卡,裂開了。


本身這是一道簡單的樹揹包問題。關於多叉轉二叉,可以將一顆多叉樹,某個結點的左兒子是它的某一個兒子,而他的右兒子是他的兄弟。

void makefa(int x,int fx) {
	rc[x] = lc[fx];
	lc[fx] = x;
}

這樣,我們就成功將一個多叉的樹轉成了二叉樹,在一些用二叉樹做的題上很有優勢。關於森林上如何動態規劃的問題,可以新增一個空結點作為全祖先,然後將各棵樹的頭向該空結點相連即可。

點選檢視程式碼
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<bitset>
#include<queue>
#include<vector>
#include<cstdio>
#include<cmath>

using namespace std;
const int maxn = 105;
int m,n,rt;
int vl[maxn],lc[maxn],rc[maxn];
void makefa(int x,int fx) {
	rc[x] = lc[fx];
	lc[fx] = x;
}
int dp[maxn][maxn];
void dfs(int x,int y) {
	if((!x)||(!y)) return;
	if(dp[x][y]>0) return;
	dfs(rc[x],y);
	dp[x][y] = dp[rc[x]][y];
	for(int i=0;i<y;i++) {
		dfs(lc[x],i); dfs(rc[x],y-i-1);
		dp[x][y] = max(dp[x][y],vl[x]+dp[lc[x]][i]+dp[rc[x]][y-i-1]);
	}
}
int main(){
    scanf("%d%d",&m,&n);
    rt = m+1;
    for(int i=1;i<=m;i++) {
        int x; scanf("%d%d",&x,&vl[i]);
		if(x==0) x = rt;
		makefa(i,x);
	}
	dfs(rt,n+1);
	printf("%d",dp[rt][n+1]);
    return 0;
}