1. 程式人生 > 遊戲攻略 >《原神攻略》2.0版鳴草收集路線推薦

《原神攻略》2.0版鳴草收集路線推薦

題目傳送門

一、理解與感悟

種類並查集的模板題。

相關資料:
https://zhuanlan.zhihu.com/p/97813717

相關試題:
https://www.cnblogs.com/littlehb/p/15111650.html

二、完整程式碼

#include <bits/stdc++.h>

using namespace std;

int n;//人數
int m;//關係數
char opt;//F: 代表 p 與 q 為朋友;E:代表 p 與 q 為敵人。
int p, q;//兩個人員
int cnt;//最終的集合數量
//輸出:一行一個整數代表最多的團體數

const int N = 1000 * 2 + 10;
//fa[i]表示i所屬的集合,用fa[i+n]表示i所屬集合的補集,實現的很巧妙,可以當成一個使用並查集的巧妙應用;
int fa[N];    //並查集陣列,有時也寫成 N << 1 ,從左到右,讀作N左移1位,就是 2*N

//要深入理解這個遞歸併壓縮的過程
int find(int x) {
    if (fa[x] != x) fa[x] = find(fa[x]);
    return fa[x];
}

//加入家族集合中
void join(int c1, int c2) {
    int f1 = find(c1), f2 = find(c2);
    if (f1 != f2)fa[f1] = f2;
}

/**
測試用例:
6
4
E 1 4
F 3 5
F 4 6
E 1 2

答案:
3
*/
int main() {
    //輸入人數與關係數
    cin >> n >> m;

    //初始化並查集
    for (int i = 1; i <= 2 * n; i++)fa[i] = i;

    //輸入關係
    for (int i = 1; i <= m; i++) {
        cin >> opt >> p >> q;
        switch (opt) {
            case 'E':
                join(q + n, p);
                join(p + n, q);
                break;
            case 'F':
                join(p, q);       //把p加入到q的家族中
                break;
        }
    }
    //找出最終的集合數量
    for (int i = 1; i <=  n; i++) if (fa[i] == i)cnt++;
    //輸出
    cout << cnt << endl;
    return 0;
}