AtCoder

ABC361 E問題(Tree and Hamilton Path 2)を解く

AtCoder_ABC361_E

AtCoder が提供しているABC(AtCoder Beginner Contest)361 E問題をC++とPythonで解いてみました。ABC361は、2024年7月6日21:00に実施されました。

AtCoder の紹介はこちらに、プログラミングの方針はこちらに記事があります。

E問題 Tree and Hamilton Path 2(Difficulty : 1213)

問題の詳細は、リンク先をご覧ください。

ABC361 E問題 Tree and Hamilton Path 2

1周する移動距離から木の直径を引きます。AtCoder Problems による Difficulty は 1213 でした。

解答案

もし、1周するのであれば、すべての頂点を往復する移動の最小距離は、$2 \times \sum C_i$ となります。どの頂点から始めても同じです。

今回の問題は、1周する必要がないため、木の直径(最も遠い頂点間の距離)を $2 \times \sum C_i$ から引けば、求める解となります。直感的に分からなくもないです。厳密な証明は、公式解説をご覧ください。

C++ プログラム例(ABC361E)

前日の記事で、木の直径について解説しました。DFSでもBFSでも解けますが、この記事では、BFSを使ったプログラムを紹介します。移動距離の和の2倍から直径を引いている以外は、前日の記事のプログラムと同じです。

以下が、C++プログラムです。

#include <bits/stdc++.h>
using namespace std;

typedef long long int ll;
struct Edge {
	int to;
	ll weight;
	Edge() { }
	Edge(int t, ll w) : to(t), weight(w) { }
};

int main()
{
	int n;
	cin >> n;
	ll result = 0;
	vector<vector<Edge>> G(n);
	for (int i = 0; i < n - 1; ++i) {
		int a, b;
		ll c;
		cin >> a >> b >> c;
		--a;
		--b;
		G[a].push_back(Edge(b, c));
		G[b].push_back(Edge(a, c));
		result += 2 * c;
	}

	vector<ll> dist(n, -1);
	queue<int> que;
	que.push(0);
	dist[0] = 0;
	int max_v = 0;
	ll max_dist = 0;
	while (!que.empty()) {
		int now = que.front();
		que.pop();
		for (auto next_v : G[now]) {
			if (dist[next_v.to] == -1) {
				que.push(next_v.to);
				dist[next_v.to] = dist[now] + next_v.weight;
				if (dist[next_v.to] > max_dist) {
					max_v = next_v.to;
					max_dist = dist[next_v.to];
				}
			}
		}
	}

	dist.assign(n, -1);
	que.push(max_v);
	dist[max_v] = 0;
	max_dist = 0;
	while (!que.empty()) {
		int now = que.front();
		que.pop();
		for (auto next_v : G[now]) {
			if (dist[next_v.to] == -1) {
				que.push(next_v.to);
				dist[next_v.to] = dist[now] + next_v.weight;
				max_dist = max(max_dist, dist[next_v.to]);
			}
		}
	}

	result -= max_dist;

	cout << result << endl;

	return 0;
}

AC(Accepted=正しいプログラム)と判定されました。

Python プログラム例(ABC361E)

Python版も基本的な考え方は同じです。キューは deque を使いました。

"""AtCoder Beginner Contest 361 E"""
from collections import deque

n = int(input())
result = 0
G = [[] for _ in range(n)]
for i in range(n - 1):
    a, b, c = map(int, input().split())
    a -= 1
    b -= 1
    G[a].append((b, c))
    G[b].append((a, c))
    result += 2 * c

dist = [-1] * n
que = deque()
que.append(0)
dist[0] = 0
max_v = 0
max_dist = 0
while que:
    now = que.popleft()
    for next_v in G[now]:
        if dist[next_v[0]] == -1:
            que.append(next_v[0])
            dist[next_v[0]] = dist[now] + next_v[1]
            if dist[next_v[0]] > max_dist:
                max_v = next_v[0]
                max_dist = dist[next_v[0]]

dist = [-1] * n
que.append(max_v)
dist[max_v] = 0
while que:
    now = que.popleft()
    for next_v in G[now]:
        if dist[next_v[0]] == -1:
            que.append(next_v[0])
            dist[next_v[0]] = dist[now] + next_v[1]

result -= max(dist)

print(result)

どちらも「AC」と判定されました。

最後に

この機会に木の直径について学べました。

引き続き ABC の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA