题目:
一棵偶数结点的树,边带权。请将结点分成n/2对点,使每对点路径求和最小。
做法:
代码:
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false), cin.tie(0) #define debug(a) cout << #a ": " << a << using namespace std; typedef long long ll; const int N = 1e4 + 7; vector<pair<int,int> > g[N]; int mrk[N]; ll dp[N]; void dfs(int u, int p){ int cnt = 0;//记录u子树中未配对儿子数 for (int i = 0; i < g[u].size(); ++i){ int v = g[u][i].first, w = g[u][i].second; if (v == p) continue; dfs(v, u);//先处理子树v dp[u] += dp[v];//v子树的解累加进u子树 if (!mrk[v]) dp[u] += w, cnt++;//如果结点v在v子树里没下场配对,则v必定在u子树配对,边权加上,cnt++ } if (cnt%2){//未配对儿子奇数,u下场配对 mrk[u] = 1;//记录u已配对 }else{ mrk[u] = 0;//未配对儿子偶数,它们两两配对,u不下场 } } int main(void){ IOS; int T; cin >> T; while (T--){ int n; cin >> n; for (int i = 1; i <= n; ++i) g[i].clear(); memset(mrk, 0, sizeof mrk); memset(dp, 0, sizeof dp); for (int i = 0; i < n-1; ++i){ int u, v, w; cin >> u >> v >> w; g[u].push_back(make_pair(v, w)); g[v].push_back(make_pair(u, w)); } dfs(1, 1); cout << dp[1] << endl; } return 0; }