樹形dp|無根樹轉有根樹|2015年藍橋杯生命之樹
阿新 • • 發佈:2019-03-18
兩個 代碼 ima www. https 2015年 藍橋 ack 大小
2015年藍橋杯第十題——生命之樹(無根樹dfs)
①暴力解法:枚舉子集(選點) + dfs判斷連通性(題目要求連通)滿足上面兩個條件下找出最大值權值和
②dfs無根樹轉有根樹,遞歸找最優
先學習無根樹轉有根樹
參考博客:https://blog.csdn.net/Originum/article/details/82258450
參考博客:https://www.cnblogs.com/yspworld/p/4270876.html
無根樹轉有根樹模板
void dfs(int cur, int father) { for (int i = 0; i < tree[cur].size(); i++) { int son = tree[cur][i].v; if (son != father) { dfs(son, cur); // } } }
這道題思路:從根(任選一個作為根)出發,自根向下遞歸、自下向上回溯,選取最優(dp),每個節點都有兩種選擇(要、不要這個點)
無根樹的每個節點是平等的,選不同的根沒有區別。
代碼:樹上找最優
3.樹形dp
學習視頻:https://www.bilibili.com/video/av12194537?from=search&seid=7177934246567735469
代碼參考
使用dp數組存放 選當前節點和不選當前點的兩種狀態
#include<iostream> #include<algorithm> #include<vector> using namespace std; int v[100004]; int dp[100004][2];//表示選擇了當前節點和不選擇的最大分數 int vis[100004]; vector<int> node[100004]; void dfs(int t) { dp[t][1] = v[t]; dp[t][0] = 0; vis[t] = 1; for (int i = 0; i < node[t].size(); i++) { if (!vis[node[t][i]])//如果這個節點沒有走過的話 { dfs(node[t][i]);//繼續往下尋找子節點 dp[t][1] += max(dp[node[t][i]][0], dp[node[t][i]][1]);//+=是表示選當前節點時,當前節點加上當前節點的子節點的最大序列和 } else//這個子節點是不能走的 { dp[t][1] = max(dp[t][1], v[t]);//所以就比較當前序列和與當前節點的分值的大小比較 dp[t][0] = max(dp[t][0], 0); } } } int main() { int n; cin >> n; memset(vis, 0, sizeof(vis)); for (int i = 1; i <= n; i++) { cin >> v[i];//輸入分數 } int u, v; for (int i = 1; i < n; i++) { cin >> u >> v; node[u].push_back(v); node[v].push_back(u); } dfs(1); int ans = -99999; for (int i = 1; i <= n; i++) { ans = max(dp[i][1], ans); ans = max(dp[i][0], ans); } cout << ans << endl; system("pause"); return 0; }
另外一道類似的樹形dp例題:沒有上司的舞會
思路
代碼
樹形dp|無根樹轉有根樹|2015年藍橋杯生命之樹