二分圖一?二分圖判定(不連通的)
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;
}
二分圖包含連通圖和非連通圖,也就是說二分圖既有聯通的,也有非聯通的