# 題目: UVa 11228 - Transportation System

# 題目說明

有一個國家,它有許多的城市,但這些城市間沒有道路相連
政府想改變這個狀況,使一個城市可以到任意一個城市
一般距離城市間以道路相連,但如果兩個城市間的距離大於 r ,則視為不同 state,以鐵路相連
求這個國家總共有幾個 state,需要建造多長的道路及鐵路


INPUT:
第一行有一個整數 T ,代表有 T 筆測資
每筆測資第一行有兩個整數 nr

  1. n 代表城市的數量
  2. r 代表同個 state 的最遠距離
    接下來有 n 行,代表城市的座標

OUTPUT:
輸出 state 的數量、公路長度、鐵路長度

# 解題方法

先將所有的每兩個城市建一個邊並算出距離,
接著以 kruskcal 演算法,先對距離進行 sort ,再用 union_find 演算法判斷是否可連通

# 參考程式碼

#include <iostream>
#include <vector>
#include <tuple>
#include <math.h>
#include <algorithm>
using namespace std;
vector< tuple<int, int, double> > edge;
vector<int> parents;
vector<int> ranks;
int cases = 0;
double dis(pair<int, int>& edge1, pair<int, int>& edge2)
{
	return sqrt(pow(edge2.first - edge1.first, 2.0) + pow(edge2.second - edge1.second, 2.0));
}
//compare distance of every two cities
bool cmp(tuple<int, int, double> edge1, tuple<int, int, double> edge2)
{
	return get<2>(edge1) < get<2>(edge2);
}
bool union_find(int c1, int c2)
{
	// find root of c1 and c2
	while (c1 != parents[c1]) c1 = parents[c1];
	while (c2 != parents[c2]) c2 = parents[c2];
	// circle
	if (c1 == c2) return false;
	if (ranks[c1] > ranks[c2]) parents[c2] = c1;
	else if (ranks[c2] > ranks[c1]) parents[c1] = c2;
	else parents[c2] = c1, ++ranks[c1];
	return true;
}
void kruskcal(int r, int n)
{
	// sort: distance small to big
	sort(edge.begin(), edge.end(), cmp);
	int side = 0;
	int state = 1;
	double raildis = 0;
	double roaddis = 0;
	for (auto& [c1, c2, dis] : edge)
	{
		if (side == n - 1) break;
		// union_find algorithm
		if (union_find(c1, c2))
		{
			if (dis > r) raildis += dis, ++state;
			else roaddis += dis;
			++side;
		}
	}
	cout << "Case #" << ++cases << ": " << state << " " << (int)(roaddis + 0.5) << " " << (int)(raildis + 0.5) << "\n";
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int T;
	cin >> T;
	while (T--)
	{
		int n, r;
		cin >> n >> r;
		// init
		edge.clear();
		parents.clear();
		ranks.assign(n, 0);
		for (int i = 0; i < n; ++i) parents.emplace_back(i);
		// store cities
		vector< pair<int, int> > city;
		for (int i = 0, a, b; i < n; ++i)
		{
			cin >> a >> b;
			city.push_back({ a, b });
		}
		// connect every two cities and calculate the distance
		for (int i = 0; i < n; ++i)
		{
			for (int j = i + 1; j < n; ++j)
			{
				edge.push_back(make_tuple(i, j, dis(city[i], city[j])));
			}
		}
		// kruskcal algorithm
		kruskcal(r, n);
	}
	return 0;
}

# 參考資料

https://www.larrysprognotes.com/UVa%20-%2011228/