1. 程式人生 > >二分圖一?二分圖判定(不連通的)

二分圖一?二分圖判定(不連通的)



1121 : 二分圖一?二分圖判定
時間限制:10000ms
單點時限:1000ms
記憶體限制:256MB
描述

大家好,我是小Hi和小Ho的小夥伴Nettle,從這個星期開始由我來完成我們的Weekly。

新年回家,又到了一年一度大齡剩男剩女的相親時間。Nettle去姑姑家玩的時候看到了一張姑姑寫的相親情況表,上面都是姑姑介紹相親的剩男剩女們。每行有2個名字,表示這兩個人有一場相親。由於姑姑年齡比較大了記性不是太好,加上相親的人很多,所以姑姑一時也想不起來其中有些人的性別。因此她拜託我檢查一下相親表裡面有沒有錯誤的記錄,即是否把兩個同性安排了相親。

OK,讓我們愉快的暴力搜尋吧!

才怪咧。

對於拿到的相親情況表,我們不妨將其轉化成一個圖。將每一個人作為一個點(編號1..N),若兩個人之間有一場相親,則在對應的點之間連線一條無向邊。(如下圖)

img1.png
因為相親總是在男女之間進行的,所以每一條邊的兩邊對應的人總是不同性別。假設表示男性的節點染成白色,女性的節點染色黑色。對於得到的無向圖來說,即每一條邊的兩端一定是一白一黑。如果存在一條邊兩端同為白色或者黑色,則表示這一條邊所表示的記錄有誤。

由於我們並不知道每個人的性別,我們的問題就轉化為判定是否存在一個合理的染色方案,使得我們所建立的無向圖滿足每一條邊兩端的頂點顏色都不相同。

那麼,我們不妨將所有的點初始為未染色的狀態。隨機選擇一個點,將其染成白色。再以它為起點,將所有相鄰的點染成黑色。再以這些黑色的點為起點,將所有與其相鄰未染色的點染成白色。不斷重複直到整個圖都染色完成。(如下圖)

img2.png
在染色的過程中,我們應該怎樣發現錯誤的記錄呢?相信你一定發現了吧。對於一個已經染色的點,如果存在一個與它相鄰的已染色點和它的顏色相同,那麼就一定存在一條錯誤的記錄。(如上圖的4,5節點)

到此我們就得到了整個圖的演算法:

選取一個未染色的點u進行染色
遍歷u的相鄰節點v:若v未染色,則染色成與u不同的顏色,並對v重複第2步;若v已經染色,如果 u和v顏色相同,判定不可行退出遍歷。
若所有節點均已染色,則判定可行。
接下來就動手寫寫吧!

輸入

第1行:1個正整數T(1≤T≤10)

接下來T組資料,每組資料按照以下格式給出:

第1行:2個正整數N,M(1≤N≤10,000,1≤M≤40,000)

第2..M+1行:每行兩個整數u,v表示u和v之間有一條邊

輸出

第1..T行:第i行表示第i組資料是否有誤。如果是正確的資料輸出”Correct”,否則輸出”Wrong”

樣例輸入
2
5 5
1 2
1 3
3 4
5 2
1 5
5 5
1 2
1 3
3 4
5 2
3 5
樣例輸出
Wrong
Correct


#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
int t,n,m,idx;
int head[10010],color[10010];
struct A
{
    int u,v;
    int next;
} f[80010];
void build(int x,int y)
{
    f[idx].u=x;
    f[idx].v=y;
    f[idx].next=head[x];
    head[x]=idx++;
}
bool bfs(int s)
{
    queue<int> Q;
    Q.push(s);
    color[s]=1;
    while(!Q.empty())
    {
        int q=Q.front();
        Q.pop();
        for(int i=head[q]; i!=-1; i=f[i].next)
        {
            int to=f[i].v;
            if(color[to]==0)
            {
                color[to]=-color[q];
                Q.push(to);
            }
            else if(color[to]==color[q])
            {
                return false;
            }
        }
    }
    return true;
}
int main()
{
    //int vis[10010];
    scanf("%d",&t);
    while(t--)
    {
        int a,b;
        idx=0;
        //memset(vis,0,sizeof(vis));
        memset(color,0,sizeof(color));
        memset(head,-1,sizeof(head));
        scanf("%d %d",&n,&m);
        for(int i=0; i<m; i++)
        {
            scanf("%d %d",&a,&b);
            build(a,b);
            build(b,a);
        }
        int ok=0;
        for(int i=1; i<=n; i++)//必須考慮到所有的聯通分支,因為只有當所有的聯通分支滿足二分圖,它才是二分圖
        {
            if(color[i]==0)
            {
                if(!bfs(i))
                {
                    ok=1;
                    break;
                }
            }
        }
        if(!ok)
            printf("Correct\n");
        else
            printf("Wrong\n");
    }
    return 0;
}

二分圖包含連通圖和非連通圖,也就是說二分圖既有聯通的,也有非聯通的