「Solution」CodeForces 633F The Chocolate Spree
阿新 • • 發佈:2020-11-27
本題是華一高Ks 2020.11.26 T4 Attack
\(Description\)
給出一棵有\(n\)個節點的樹,每個節點有一個權值\(a_i\),求出不相交的兩條鏈的最大權值和。
\(2 \leq n \leq 10^5\)
\(1 \leq a_i \leq 10^9\)
\(Solution\)
一道樹形DP好題,難點在於狀態的轉移,即兩條鏈的形態。
不要怕多設狀態,重點在於把所有情況都描述出來。
\(DP_{now,0}: 最大兩條鏈之和\)
\(DP_{now,1}: 最大一條鏈\)
\(DP_{now,2}: 到葉子節點的鏈+一條與之不相交的鏈最大值\)
\(DP_{now,3}: 兒子節點DP_{x,1}最大值\)
\(DP_{now,4}: 到葉子節點的最大鏈\)
對於每種轉移,程式碼裡有解釋,建議在草稿紙上畫圖,對理解很有幫助。
\(AC \space Code\)
#include<iostream> #include<fstream> #include<sstream> #include<cstdio> #include<vector> #include<set> #include<queue> #include<string> #include<cstring> #include<map> #include<list> #include<deque> #include<cctype> #include<climits> #include<cmath> #include<ctime> #include<algorithm> #define File(name) freopen(name".in", "r", stdin); freopen(name".out", "w", stdout); #define Int inline int #define Void inline void #define Bool inline bool #define DB inline double #define LL inline long long #define ri register int #define re register using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double db; ll n, u, v, a[100005], dp[100005][5]; vector<int> g[100005]; LL read(){ ll n = 0; int f = 1; char ch = getchar(); while('0' > ch || ch > '9'){ if(ch == '-') f *= -1; ch = getchar(); } while('0' <= ch && ch <= '9'){ n = (n << 1) + (n << 3) + ch-'0'; ch = getchar(); } return f * n; } Void write(ll x){ if(x/10) write(x/10); putchar(x%10+'0'); } Void input() {} template<typename Type, typename... Types> Void input(Type& arg, Types&... args){ arg = read(); input(args...); } Void dfs(int now, int fa){ // 初始化 dp[now][0] = dp[now][1] = dp[now][2] = dp[now][4] = a[now]; dp[now][3] = 0; for(auto x: g[now]){ if(x == fa) continue; dfs(x, now); /* ***************************************** * * dp[][0]: 最大兩條鏈之和 * dp[][1]: 最大一條鏈 * dp[][2]: 到葉子節點的鏈+一條與之不相交的鏈最大值 * dp[][3]: 兒子節點dp[][1]最大值 * dp[][4]: 到葉子節點的最大鏈 * ***************************************** */ dp[now][0] = max(dp[now][0], dp[now][1] + dp[x][1]); // 子樹內最大一條鏈+子節點子樹內最大一條鏈 dp[now][0] = max(dp[now][0], dp[x][0]); // 從子節點直接轉移 dp[now][0] = max(dp[now][0], dp[x][2] + dp[now][4]); // 子節點子樹內到葉子節點的鏈 與 子樹內到葉子節點的鏈構成一條穿過當前節點的鏈+一條與之不相交的鏈 dp[now][0] = max(dp[now][0], dp[now][2] + dp[x][4]); // 與上面的轉移類似 dp[now][1] = max(dp[now][1], dp[x][1]); // 從子節點直接轉移 dp[now][1] = max(dp[now][1], dp[now][4] + dp[x][4]); // 子節點子樹內到葉子節點的鏈 與 子樹內到葉子節點的鏈構成一條穿過當前節點的鏈 dp[now][2] = max(dp[now][2], dp[x][2] + a[now]); // 從子節點直接轉移,將子節點子樹內那條到達葉子結點的鏈延伸到當前節點 dp[now][2] = max(dp[now][2], dp[x][4] + dp[now][3] + a[now]); // 與上面的轉移類似 dp[now][2] = max(dp[now][2], dp[now][4] + dp[x][1]); // 按照dp[][2]的定義直接轉移 dp[now][3] = max(dp[now][3], dp[x][1]); // 按照dp[][3]的定義直接轉移 dp[now][4] = max(dp[now][4], dp[x][4] + a[now]); // 按照dp[][4]的定義直接轉移,將最大鏈延伸到當前節點 } } int main(){ input(n); for(ri i = 1; i <= n; i++) input(a[i]); for(ri i = 1; i < n; i++){ input(u, v); g[u].push_back(v); g[v].push_back(u); } dfs(1, 0); write(dp[1][0]); return 0; }
- 最優解\(Rank15\)
- 1.39s
- 11.84MB
- 2.40KB