[AtCoder] ABC 157 D – Friend Suggestions
問題
方針
まず初めに、友達関係の Union-Find を作成します。このとき、人 \( i \) の友達の数を \( f_i \) として数えます。次に、人 \( i \) のブロック人数を \( b_i \) と、人 \( i \) と 人 \( j \) がブロック関係かつ 人 \( i \) と 人 \( j \) が同じグラフに所属してるとき、人 \( i \) のブロックの人数を \( b_i \) として加算します。また、\( b_j \) も加算します。人 \( i \) の連結成分の数を \( a_i \) とすると、人 \( i \) の友達候補は、\( a_i – f_i – b_i – 1 \) となります。
コード
#include <bits/stdc++.h> using namespace std; typedef long long ll; // Union-Find class DisjointSet { public: vector<int> p, rank, size; int group_num; DisjointSet(int n) { p.assign(n, 0); rank.assign(n, 0); size.assign(n, 0); group_num = n; for (int i = 0; i < n; i++) { make_set(i); } } void make_set(int x) { p[x] = x; rank[x] = 0; size[x] = 1; } bool same(int x, int y) { return find_set(x) == find_set(y);; } int find_set(int x) { if (x != p[x]) { p[x] = find_set(p[x]); } return p[x]; } int union_size(int x) { if (x != p[x]) { size[x] = union_size(find_set(x)); } return size[x]; } void link(int x, int y) { if(rank[x] > rank[y]) { p[y] = x; size[x] = size[x] + size[y]; }else if(rank[x] < rank[y]){ p[x] = y; size[y] = size[x] + size[y]; }else if(x != y) { p[y] = x; rank[x]++; size[x] = size[x] + size[y]; } } void unite(int x, int y) { if (find_set(x) != find_set(y)) group_num--; link(find_set(x), find_set(y)); } }; int main() { int N, M, K; cin >> N >> M >> K; int f[N]{}; int b[N]{}; DisjointSet ds(N); int A, B, C, D; for (int i = 0; i < M; i++) { cin >> A >> B; A--; B--; ds.unite(A, B); f[A]++; f[B]++; } for (int i = 0; i < K; i++) { cin >> C >> D; C--; D--; if (ds.same(C, D)) { b[C]++; b[D]++; } } for (int i = 0; i < N; i++) { int p = ds.union_size(i) - f[i] - b[i] - 1; if (i == N - 1) { cout << p << "\n"; } else { cout << p << " "; } } return 0; }
ディスカッション
コメント一覧
まだ、コメントがありません