CF1559D1. Mocha and Diana (Easy Version)
阿新 • • 發佈:2021-08-16
原題連結:1559D1. Mocha and Diana (Easy Version)
題意:
小明和小紅各有一個具有\(n\)個結點的森林,現執行操作:
- 加一條邊,使得兩人的森林還是森林
- 小明加一條\((u, v)\)的邊,那麼小紅也必須加一條\((u, v)\)的邊。
問我們最多能加多少邊?
思路:
很明顯,第一個條件沒啥用,關鍵是第二個條件,我們知道如果一個人不能加\((u, v)\)一條邊的前提條件是\(u\)與\(v\)已經聯通,那麼根據這個條件,我們可以使用並查集,而邊的資料範圍是\([1-1000]\),所以可以直接暴力列舉點,然後使用並查集來判斷兩個點是否已經在一個集合內,如果在一個集合內那麼就不能加邊了,否則加上即可。
#include <bits/stdc++.h> using namespace std; const int N = 1010; int fa1[N], fa2[N]; int find1(int x) { if (x != fa1[x]) fa1[x] = find1(fa1[x]); return fa1[x]; } int find2(int x) { if (x != fa2[x]) fa2[x] = find2(fa2[x]); return fa2[x]; } int main() { ios::sync_with_stdio(false), cin.tie(0); int n, m1, m2; cin >> n >> m1 >> m2; for (int i = 1; i <= n; i++) fa1[i] = i, fa2[i] = i; while (m1--) { int a, b; cin >> a >> b; fa1[find1(a)] = find1(b); } while (m2--) { int a, b; cin >> a >> b; fa2[find2(a)] = find2(b); } vector<pair<int, int>> add; for (int i = 1; i <= n; i++) { for (int j = i + 1; j <= n; j++) { int u1 = find1(i), v1 = find1(j); int u2 = find2(i), v2 = find2(j); if (u1 != v1 && u2 != v2) { add.push_back({i, j}); fa1[u1] = v1; fa2[u2] = v2; } } } cout << add.size() << endl; for (int i = 0; i < add.size(); i++) cout << add[i].first << " " << add[i].second << endl; return 0; }
注意:
題目思路並不難,但是我耗了一個多小時,原因:
我一開始\(find\)函式寫成了這樣。
int find1(int x) {
if (x == fa1[x]) return x;
return find1(fa1[x]);
}
乍一看沒錯,確實沒錯,就是\(T\)到飛起,為啥,因為沒有加入路徑壓縮的優化,所以\(T\)到飛起,我服了,這次長記性了。
另外,以後並查集用一個類吧,貼個板子:
struct DSU{ int fa[N], Size[N]; void init() { for (int i = 1; i <= n; i++) fa[i] = i; } int find(int x) { if (x != fa[x]) fa[x] = find(fa[x]); return fa[x]; } void merge(int x, int y) { Size[find(x)] += Size[find(y)]; fa[find(x)] = find(y); } bool check(int x, int y) { return find(x) == find(y); } }dsu1, dsu2;