原題:
https://cses.fi/problemset/task/1130
題意:
給一棵 n 點無根樹,選一些邊,使得任兩條選中的邊不共享端點(匹配)。求可選邊數最大值。
解題思路:
#include <bits/stdc++.h>
using namespace std;
const int INF_NEG = -1e9;
int n;
vector<vector<int>> g;
vector<array<int,2>> dp; // dp[u][0/1]
void dfs(int u, int p){
int base = 0;
for(int v: g[u]) if(v!=p){
dfs(v, u);
base += max(dp[v][0], dp[v][1]);
}
dp[u][0] = base;
int bestGain = INF_NEG;
for(int v: g[u]) if(v!=p){
int gain = dp[v][0] + 1 - max(dp[v][0], dp[v][1]);
bestGain = max(bestGain, gain);
}
dp[u][1] = (bestGain==INF_NEG ? INF_NEG : base + bestGain);
}
int main(){
ios::sync_with_stdio(false); cin.tie(nullptr);
cin >> n;
g.assign(n+1, {});
for(int i=0;i<n-1;i++){
int a,b; cin>>a>>b;
g[a].push_back(b); g[b].push_back(a);
}
dp.assign(n+1, {0, INF_NEG});
dfs(1, 0);
cout << max(dp[1][0], dp[1][1]) << "\n";
return 0;
}
原題:
https://cses.fi/problemset/task/1133
題意:
給一棵 n 點樹,對每個節點 u,輸出 sum_{v} dist(u, v)。
解題思路(換根 DP)
#include <bits/stdc++.h>
using namespace std;
int n;
vector<vector<int>> g;
vector<long long> ans;
vector<int> sz;
void dfs1(int u, int p, int depth, long long &sumDepth){
sz[u] = 1;
sumDepth += depth;
for(int v: g[u]) if(v!=p){
dfs1(v, u, depth+1, sumDepth);
sz[u] += sz[v];
}
}
void dfs2(int u, int p){
for(int v: g[u]) if(v!=p){
// reroot: move root from u to v
ans[v] = ans[u] + (long long)n - 2LL*sz[v];
dfs2(v, u);
}
}
int main(){
ios::sync_with_stdio(false); cin.tie(nullptr);
cin>>n;
g.assign(n+1, {});
for(int i=0;i<n-1;i++){
int a,b; cin>>a>>b;
g[a].push_back(b); g[b].push_back(a);
}
ans.assign(n+1, 0);
sz.assign(n+1, 0);
long long sumDepth = 0;
dfs1(1, 0, 0, sumDepth);
ans[1] = sumDepth;
dfs2(1, 0);
for(int i=1;i<=n;i++){
cout << ans[i] << (i==n?'\n':' ');
}
return 0;
}
原題:
https://leetcode.com/problems/house-robber-iii/description/
題意:
二元樹,每個節點有金額。不能同時搶相鄰節點(父子不能同取)。求最大總額。
解題思路
/**
* Definition for a binary tree node.
* struct TreeNode { int val; TreeNode *left; TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *l, TreeNode *r) : val(x), left(l), right(r) {}
* };
*/
class Solution {
pair<int,int> dfs(TreeNode* u){
if(!u) return {0,0}; // {notTake, take}
auto L = dfs(u->left);
auto R = dfs(u->right);
int take = u->val + L.first + R.first;
int notTake = max(L.first, L.second) + max(R.first, R.second);
return {notTake, take};
}
public:
int rob(TreeNode* root) {
auto [a,b] = dfs(root);
return max(a,b);
}
};
原題:
https://leetcode.com/problems/binary-tree-maximum-path-sum/
題意:
二元樹中任意兩節點之間的路徑和最大值(路徑必須連續向下或經過某節點轉彎;可為單點)。
解題思路:
class Solution {
int best = INT_MIN;
int gain(TreeNode* u){
if(!u) return 0;
int L = max(0, gain(u->left));
int R = max(0, gain(u->right));
best = max(best, u->val + L + R); // 經過 u 作為峰頂
return u->val + max(L, R); // 向上一條鏈
}
public:
int maxPathSum(TreeNode* root) {
gain(root);
return best;
}
};