朋友

土木牢盖發表於2024-11-27

朋友

題目背景

小明在 A 公司工作,小紅在 B 公司工作。

題目描述

這兩個公司的員工有一個特點:一個公司的員工都是同性。

A 公司有 \(N\) 名員工,其中有 \(P\) 對朋友關係。B 公司有 \(M\) 名員工,其中有 \(Q\) 對朋友關係。朋友的朋友一定還是朋友。

每對朋友關係用兩個整數 \((X_i,Y_i)\) 組成,表示朋友的編號分別為 \(X_i,Y_i\)。男人的編號是正數,女人的編號是負數。小明的編號是 \(1\),小紅的編號是 \(-1\)

大家都知道,小明和小紅是朋友,那麼,請你寫一個程式求出兩公司之間,透過小明和小紅認識的人最多一共能配成多少對情侶(包括他們自己)。

輸入格式

輸入的第一行,包含 \(4\) 個空格隔開的正整數 \(N,M,P,Q\)

之後 \(P\) 行,每行兩個正整數 \(X_i,Y_i\)

之後 \(Q\) 行,每行兩個負整數 \(X_i,Y_i\)

輸出格式

輸出一行一個正整數,表示透過小明和小紅認識的人最多一共能配成多少對情侶(包括他們自己)。

樣例

樣例輸入

4 3 4 2
1 1
1 2
2 3
1 3
-1 -2
-3 -3

樣例輸出

2

提示

對於 \(30 \%\) 的資料,\(N,M \le 100\)\(P,Q \le 200\)

對於 \(80 \%\) 的資料,\(N,M \le 4 \times 10^3\)\(P,Q \le 10^4\)

對於 \(100 \%\) 的資料,\(N,M \le 10^4\)\(P,Q \le 2 \times 10^4\)

[!TIP]

並查集

#include <bits/stdc++.h>
using namespace std;
const int N = 2e4 + 10;
int n, m, p, q, x, y;
int f[N], g[N];

// 查詢函式
int find1(int x) {
    if (f[x] == x) {
        return x;
    } else {
        return f[x] = find1(f[x]);
    }
}
int find2(int x) {
    if (g[x] == x) {
        return x;
    } else {
        return g[x] = find2(g[x]);
    }
}

// 合併函式
void baka1(int x, int y) {
    int findX = find1(x);
    int findY = find1(y);
    if (findX != findY) {
        f[findX] = findY;
    }
}

void baka2(int x, int y) {
    int findX = find2(x);
    int findY = find2(y);
    if (findX != findY) {
        g[findX] = findY;
    }
}

int main() {
    scanf("%d %d %d %d", &n, &m, &p, &q);

    // 初始化
    for (int i = 1; i <= n; i++) {
        f[i] = i;
    }
    for (int i = 1; i <= m; i++) {
        g[i] = i;
    }

    //合併A
    for (int i = 0; i < p; i++) {
        scanf("%d %d", &x, &y);
            baka1(x, y);
    }

    //合併B
    for (int i = 0; i < q; i++) {
        scanf("%d %d", &x, &y);
            baka2(-x, -y); // B公司員工性別為女,編號為負,要取反
        }
    }
    int FFF1 = 0, FFF2 = 0;//FFF是單身狗最後的倔強
    for (int i = 1; i <= n; i++) {
        if (find1(i) == find1(1)) {
            FFF1++;
        }
    }
    for (int i = 1; i <= m; i++) {
        if (find2(i) == find2(1)) {
            FFF2++;
        }
    }
    printf("%d\n", min(FFF1, FFF2));

    return 0;
}

我們也可以透過定義fumo來區分,從而合併find 和 baka

#include <bits/stdc++.h>
using namespace std;
const int N = 2e4 + 10;
int n, m, p, q, x, y;
int f[N], g[N];

// 查詢函式
int find(int x, int fumo) {
    if (fumo == 1) {
        if (f[x] == x) {
            return x;
        } else {
            return f[x] = find(f[x], fumo);
        }
    } else if (fumo == 2) {
        
        if (g[x] == x) {
            return x;
        } else {
            return g[x] = find(g[x], fumo);
        }
    }
}

// 合併函式(用fumo區分AB)
void baka(int x, int y, int fumo) {
    int findX = find(x, fumo);
    int findY = find(y, fumo);
    if (findX!= findY) {
        if (fumo == 1) {//A
            f[findX] = findY;
        } else if (fumo == 2) {//B
            g[findX] = findY;
        }
    }
}

int main() {
    scanf("%d %d %d %d", &n, &m, &p, &q);
    // 初始化(員工只和自己有朋友關係)
    for (int i = 1; i <= n; i++) 
	{
        f[i] = i;
    }
    for (int i = 1; i <= m; i++) 
	{
        g[i] = i;
    }
    // 合併A
    for (int i = 0; i < p; i++) 
	{
        scanf("%d %d", &x, &y);
        baka(x, y, 1);
    }
    // 合併B
    for (int i = 0; i < q; i++) 
	{
        scanf("%d %d", &x, &y);
        baka(-x, -y, 2); //B公司員工性別為女,編號為負,要取反
    }
    // 統計與小明(1)和小紅(反1)的朋友關係數量
    int FFF1 = 0, FFF2 = 0;//定義為FFF是單身狗最後的倔強
    for (int i = 1; i <= n; i++) {
        if (find(i, 1) == find(1, 1)) 
		{
            FFF1++;
        }
    }
    for (int i = 1; i <= m; i++) {
        if (find(i, 2) == find(1, 2)) 
		{
            FFF2++;
        }
    }
    printf("%d\n", min(FFF1, FFF2));
    return 0;
}



相關文章