2485 Highways
n個の町を高速道路で繋ぐ計画。
どの町にも高速を使ってアクセスできるようにするとき、町間の高速道路の長さの最大値が
最小になるような計画を立てて、最大値を答える問題。
最少全域木問題だから、貪欲法で解ける。
初めてunion findを使ったから記念に。
DisjointSetクラスのメソッドたち
注意点としてはmakeSet(x)する前にfindSet(x)!=0でxを含む集合が存在しないことを確認すること。
・void makeSet(int x) xだけからなる集合を作る
・void myunion(int x, int y) xとyを合併する
・int findSet(int x) xが含まれる集合の代表を求める
・bool isSameSet(int x, int y) xとyが同じ集合に含まれればtrue
あと、このDisjointSetだとmakeSet(0)ができないので注意。(0で集合が存在しないことを示しているため)
#include<cstdio> #include<vector> #include<queue> using namespace std; // 町i-j間の距離はd struct Dist { int d, i, j; Dist(int d, int i, int j) : d(d), i(i), j(j) {} bool operator < (const Dist &dist) const { return d > dist.d; } }; // union find用 class DisjointSet{ public: DisjointSet(){} DisjointSet( int size ){ rank.resize( size, 0 ); p.resize( size, 0 ); } void makeSet( int x ){ p[x] = x; rank[x] = 0; } void myunion( int x, int y ){ link( findSet(x), findSet(y) ); } int findSet( int x ){ if ( x != p[x] ) p[x] = findSet( p[x] ); return p[x]; } bool isSameSet( int x, int y ){ return ( findSet(x) == findSet(y) ); } private: vector<int> rank, p; void link ( int x, int y ){ if ( rank[x] > rank[y] ){ p[y] = x; } else { p[x] = y; if ( rank[x] == rank[y] ) rank[y]++; } } }; int main() { int t; scanf("%d", &t); while (t--) { int n; scanf("%d", &n); priority_queue<Dist> Q; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { int d; scanf("%d", &d); if (j > i) Q.push(Dist(d, i, j)); } } DisjointSet DS = DisjointSet(n+1); int ret = 0; for (int cnt = 0; cnt < n-1; ) { // 道をn-1本作ったら全域木になる Dist dist = Q.top(); Q.pop(); if (!DS.findSet(dist.i)) DS.makeSet(dist.i); if (!DS.findSet(dist.j)) DS.makeSet(dist.j); if (DS.isSameSet(dist.i, dist.j)) continue; DS.myunion(dist.i, dist.j); ret = dist.d; ++cnt; } printf("%d\n", ret); } }