博客 / 詳情

返回

CF161D Distance in Tree + 樹上揹包

CF161D Distance in Tree

DP狀態定義

根據子樹位置\(+\)路徑長度的統計設計狀態。

\(Dp_{u,j}\)表示在以 \(u\) 為根的子樹中,到 \(u\) 的距離恰好為 \(j\) 的節點個數。

初始化

\[dp_{u, 0}=1 \]

狀態轉移方程式

在合併子樹時來統計答案

\[ans = ans + \sum^k_{j=0}dp_{u,j} \times dp_{j,k-1-j} \]

處理完答案後再合併子樹:

\[dp_{u,j}=dp_{u,j}\sum^k_{j=1}dp_{v,j-1} \]

戳我看代碼
void dfs(int u, int fa) {
	dp[u][0] = 1;
	for (auto v : g[u]) {
		if (fa == v) continue;
		dfs(v, u);
		rep(j, 0, k - 1) ans += dp[u][j] * dp[v][k - 1 - j];
		rep(j, 1, k) dp[u][j] += dp[v][j - 1];
	}
}

最重要的,樹上揹包!

例題:[CTSC1997] 選課

狀態定義

\(dp_{u,i,j}\)表示在 \(u\) 這裏,前 \(i\) 棵子樹,共計選擇 \(j\) 門課,共可以獲得的最大貢獻。

狀態轉移

自己先想想,很簡單,或者看代碼。

戳我看代碼
void dfs(int u){
	for(auto v:graph[u]){
		dfs(v); // 先遞歸求出子樹的答案
	}
	
	dp[u][0][1] = score[u];
	for(int i=1;i<=graph[u].size();i++){
		int v=graph[u][i-1];
		int siz_v=graph[v].size(); // 標記1
		for(int j=1;j<=m+1;j++){ // 至少選自己這門課,才可以考慮子樹
			dp[u][i][j]=dp[u][i-1][j]; // 不選 v 子樹,直接繼承。
			// 選 v 子樹,枚舉選多少
			for(int k=0;k<=m+1;k++) if(j>k){//至少選自己這門課,才可以考慮子樹
				dp[u][i][j]=max(dp[u][i][j],dp[u][i-1][j-k]+dp[v][siz_v][k])
			}
		}
	}
}


user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.