Shortest Path(树形DP)
Shortest Path
https://ac.nowcoder.com/acm/problem/13886
题目:
一棵偶数结点的树,边带权。请将结点分成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;
}
查看22道真题和解析
