快轉到主要內容

CSES-1668 Building Teams

目錄

題目連結:https://cses.fi/problemset/task/1668

題意
#

Uolevi 的班上有 \(n\) 個學生,另外還有 \(m\) 對好朋友關係。你的任務是幫他們分成兩個不同的隊伍,唯一的條件是:「不能有任何一對好朋友被分在同一個隊伍裡」。

如果可以成功分隊,請印出每個學生被分到哪一隊(輸出 1 或 2,任意一種合法的分法皆可);如果不管怎麼分,都一定會有好朋友被塞在同一隊被迫互相廝殺,就印出 IMPOSSIBLE

思路
#

這題本質上就是「二分圖(Bipartite Graph)」的判定問題。我們要確認一張圖的節點,能不能單純被塗成兩種顏色,而且所有相鄰的節點(也就是牽涉到好朋友關係的兩個人)顏色都不一樣。

要解二分圖,最經典的做法就是「圖著色(Graph Coloring)」,可以用 DFS 或 BFS 來實作,概念都一樣。這裡我們採用 DFS 會簡單乾脆一點。

我們會依序巡視每一個學生,如果他還沒有被分到任何隊伍,我們就先私自把他指派到「第 1 隊」,然後沿著他的朋友圈開始深搜(DFS)。每次找到他的好朋友,就強制把對方分進「另一隊」(利用 3 - 原隊伍編號 的技巧,可以輕易達成 1 變 2、2 變 1 的切換)。

如果在深搜的過程中,我們不幸撞見某個好朋友「剛好被分在跟自己同一隊」,那就代表產生了衝突。此時我們就可以立刻宣告這班學生的交友關係太過錯綜複雜,絕對湊不齊兩個單純的隊伍,直接翻桌(記錄 flag = 0 表示無解)即可。

程式碼
#

#include <bits/stdc++.h>
using namespace std;

#define pb push_back
#define fi first
#define se second
#define INF LONG_LONG_MAX/1000
#define WA() cin.tie(0)->sync_with_stdio(0)
#define all(x) (x).begin(), (x).end()
#define int long long
#define PII pair<int, int>

vector<vector<int>> v;
vector<int> vis; // 用來記錄分隊狀態:0 表示未分隊,1 表示隊伍 1,2 表示隊伍 2
int flag = 1;    // 判斷是否能成功分隊的旗標

// 透過 DFS 將相鄰的好朋友分到不同的隊伍(經典二分圖著色)
void dfs(int x) {
    for (auto u : v[x]) {
        if (!vis[u]) {
            vis[u] = 3 - vis[x]; // 小技巧:將 1 轉 2,將 2 轉 1
            dfs(u); // 繼續往深處著色
        }
        else if (flag) {
            // 如果朋友 u 已經有隊伍了,檢查他的隊伍是不是跟 x 一樣
            // 如果撞隊了,flag 就會變成 0(false),代表發生衝突不可能完成
            flag = vis[x] != vis[u];
        }
    }
}

signed main() { WA();
    int n, m; cin >> n >> m;
    v.resize(n+1);
    vis.resize(n+1);
    
    // 讀入所有的好朋友關係(建立雙向無向圖)
    while (m--) {
        int a, b; cin >> a >> b;
        v[a].pb(b);
        v[b].pb(a);
    }
    
    // 可能有多個不連通的朋友圈,每個學生都要當頭試試看
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            vis[i] = 1; // 隨意指派未分隊的頭為 1 號隊伍
            dfs(i);
        }
    }
    
    if (flag) {
        // 分隊成功,印出所有學生的所屬隊伍
        for (int i = 1; i <= n; i++) cout << vis[i] << ' ';
    }
    else {
        // 抓到衝突代表交友關係無法被切成二分圖,輸出無解
        cout << "IMPOSSIBLE\n";
    }
}
Piau 的筆記本
作者
Piau 的筆記本
希望我寫下來的東西能夠長久的記在我的腦中