並查集 - 紅色警報 - 天梯賽 L2-013

njuptACMcxk發表於2020-11-25

並查集 - 紅色警報 - 天梯賽 L2-013

題意:

給 定 一 個 n 個 點 m 條 邊 的 無 向 圖 , 給定一個n個點m條邊的無向圖, nm

接 著 進 行 k 次 操 作 , 每 次 去 除 圖 中 的 一 個 點 , 判 斷 這 個 點 是 否 是 該 點 所 在 連 通 塊 的 割 點 。 接著進行k次操作,每次去除圖中的一個點,判斷這個點是否是該點所在連通塊的割點。 k

輸入:

首 行 兩 個 正 整 數 n 和 m , 首行兩個正整數n和m, nm

接 著 m 行 , 每 行 分 別 包 含 兩 個 整 數 , 表 示 一 條 邊 的 兩 個 端 點 接著m行,每行分別包含兩個整數,表示一條邊的兩個端點 m

然 後 一 個 正 整 數 k , 然後一個正整數k, k

最 後 一 行 為 k 個 整 數 , 按 照 次 序 移 除 每 個 點 。 最後一行為k個整數,按照次序移除每個點。 k

輸出:

若 當 前 移 除 的 點 a i 不 是 該 點 所 在 連 通 塊 的 割 點 , 則 輸 出 : 若當前移除的點a_i不是該點所在連通塊的割點,則輸出: aiCity ai is lost.

否 則 輸 出 : 否則輸出: Red Alert: City ai is lost!

注意: 當 圖 中 的 n 個 點 都 被 移 除 後 , 要 輸 出 : 當圖中的n個點都被移除後,要輸出: nGame Over.

Game Over. 的 條 件 是 n 個 點 都 被 移 除 , 而 非 完 成 k 次 操 作 。 這 裡 是 本 題 一 個 坑 點 。 的條件是n個點都被移除,而非完成k次操作。這裡是本題一個坑點。 nk

輸入樣例:

5 4
0 1
1 3
3 0
0 4
5
1 2 0 4 3

輸出樣例:

City 1 is lost.
City 2 is lost.
Red Alert: City 0 is lost!
City 4 is lost.
City 3 is lost.
Game Over.

資料範圍: N(0 < N ≤ 500)和M(≤ 5000),分別為城市個數(於是預設城市從0到N-1編號)和連線兩城市的通路條數。


分析:

看 這 個 數 據 範 圍 , 可 以 暴 力 ( 亂 搞 ) 看這個資料範圍,可以暴力(亂搞) ()

如 果 一 個 點 是 割 點 , 那 麼 把 這 個 點 獨 立 出 來 之 後 , 整 個 圖 中 連 通 塊 的 數 量 至 少 增 加 2. 如果一個點是割點,那麼把這個點獨立出來之後,整個圖中連通塊的數量至少增加2. 2.

接 下 來 的 問 題 就 是 如 何 用 統 計 連 通 塊 的 數 量 。 接下來的問題就是如何用統計連通塊的數量。

利 用 並 查 集 統 計 連 通 塊 的 數 量 , 判 斷 條 件 : F i n d ( i ) = = i , 也 就 是 統 計 根 的 數 量 。 利用並查集統計連通塊的數量,判斷條件:Find(i)==i,也就是統計根的數量。 Find(i)==i

我 們 每 次 獨 立 一 個 點 以 後 , 對 新 圖 再 用 並 查 集 合 並 , 重 新 統 計 連 通 塊 的 數 量 , 我們每次獨立一個點以後,對新圖再用並查集合並,重新統計連通塊的數量,

然 後 用 上 一 次 統 計 的 連 通 塊 數 量 c n t 與 本 次 統 計 的 連 通 塊 數 量 c n t 1 作 差 , 判 斷 。 然後用上一次統計的連通塊數量cnt與本次統計的連通塊數量cnt1作差,判斷。 cntcnt1

可 以 用 一 個 b o o l 數 組 把 新 獨 立 出 的 點 標 記 出 來 , 合 並 的 時 候 過 濾 到 包 含 這 些 點 的 邊 。 可以用一個bool陣列把新獨立出的點標記出來,合併的時候過濾到包含這些點的邊。 bool

程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#include<vector>

#define P pair<int,int>
#define u first
#define v second
#define ll long long

using namespace std;

const int N = 510, M = 5010;

int n, m, k;
int p[N];
P E[M];
int cnt, cnt1;
bool st[N];

void Init()
{
    for(int i=1;i<=n;i++) p[i]=i;
}

int Find(int x)
{
    if(p[x]!=x) p[x]=Find(p[x]);
    return p[x];
}

void unite(int a,int b)
{
    a=Find(a), b=Find(b);
    p[a]=b;
}

int main()
{
    scanf("%d%d",&n,&m);
    Init();
    
    for(int i=0;i<m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        u++, v++;
        E[i]={u,v};
        unite(u,v);
    }
    
    for(int i=1;i<=n;i++)
        if(Find(i)==i)
            cnt++;
    
    scanf("%d",&k);
    for(int i=1;i<=k;i++)
    {
        int t;
        scanf("%d",&t);
        t++;
        Init();
        st[t]=true;
        for(int j=0;j<m;j++)
        {
            int u=E[j].u, v=E[j].v;
            if(st[u]||st[v]) continue;
            unite(u,v);
        }
        
        for(int j=1;j<=n;j++)
            if(Find(j)==j)
                cnt1++;
                
        if(cnt1-cnt>1) printf("Red Alert: City %d is lost!\n",t-1);
        else printf("City %d is lost.\n",t-1);
        cnt=cnt1;
        cnt1=0;
        
        if(i==n)
        {
            puts("Game Over.");
            break;
        }
    }
    
    return 0;
}

相關文章