Shortest Path(4月3日题目 DFS 树)

19 篇文章 0 订阅
9 篇文章 0 订阅

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值