Shortest Path
https://ac.nowcoder.com/acm/problem/13886
https://ac.nowcoder.com/discuss/398540
题意:
给你一棵有
n
n
n 个点的树(
n
n
n 是偶数),你需要将
n
n
n 个点分为
n
/
2
n/2
n/2 个点对,使得每个点对的两点间的距离和最小。
思路:
边不能重复选,如果选了重复的边,那么肯定可以找到一种距离和更短的方法把重复的边去掉。
对这棵树来说,如果子树的节点数(包括自己)是偶数,那么这棵子树可以完成点对的配对,如果是奇数,那么它只能与它的父节点相连。
题目给出的题意解法不明显,但是把问题转换后就很简单了😲
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct edge {
ll to, w, next;
edge(ll to=0, ll w=0, ll next=0):to(to),w(w),next(next){}
} e[20010];
int head[10010], cnt, tot[10010];
ll ans;
void add(ll u, ll v, ll w) {
cnt++;
e[cnt] = edge(v, w, head[u]);
head[u] = cnt;
}
void dfs(ll u, ll fa, ll len) {
tot[u] = 1;
for (int i = head[u]; i != -1; i = e[i].next) {
ll v = e[i].to;
if (v == fa) continue;
dfs(v, u, e[i].w);
tot[u] += tot[v];
}
if (tot[u] & 1) ans += len;
}
int main() {
ios::sync_with_stdio(false);
ll T, n, u, v, w;
cin >> T;
while (T--) {
ans = 0;
cnt = 0;
memset(head, -1, sizeof(head));
memset(tot, 0, sizeof(tot));
cin >> n;
for (int i = 1; i < n; i++) {
cin >> u >> v >> w;
add(u, v, w);
add(v, u, w);
}
dfs(1, 0, 0);
cout << ans << endl;
}
return 0;
}
Code2:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node {
ll v, w;
};
vector<node> e[10010];
vector<ll> cnt(10010);
ll ans;
void dfs(ll cur, ll pre, ll len) {
cnt[cur] = 1;
for (int i = 0; i < e[cur].size(); i++) {
ll v = e[cur][i].v;
if (v == pre) continue;
dfs(v, cur, e[cur][i].w);
cnt[cur] += cnt[v];
}
if (cnt[cur] & 1) ans += len;
}
int main() {
ios::sync_with_stdio(false);
ll T, n, u, v, w;
cin >> T;
while (T--) {
cin >> n;
ans = 0;
cnt.clear();
for (int i = 1; i <= n; i++) e[i].clear();
for (int i = 1; i < n; i++) {
cin >> u >> v >> w;
e[u].push_back({v, w});
e[v].push_back({u, w});
}
dfs(1, 0, 0);
cout << ans << endl;
}
return 0;
}