Bicoloring (并查集/二分图)

题目链接

题意:

  m个查询,每个查询输入a b,表示 顶点a b之间涂色。 规定只能涂颜色0 或者颜色 1,一个节点相连的边 必须涂成相同的颜色。 问 ,输入m组 a b之后,会不会犯规。

思路:

  判断 a b 所在的环 边的数量 是奇还是偶。 奇数就不能,偶数就能。

  用并查集: 找到他们公共的祖先,判断(a到祖先的距离 + b到祖先的距离 +1 )的奇偶(最近的公共祖先 还是最远的公共祖先 都没关系,不影响奇偶) 。  如果a b没有公共祖先,就 f [fa] = fb合并起来就行

#include<iostream>
#include<cstdio>
#include <cctype>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<cmath>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<map>
using namespace std;
#define ll long long
#define mem(a,x) memset(a,x,sizeof(a))
#define se second
#define fi first
const ll mod=998244353;
const int INF= 0x3f3f3f3f;
const int N=2e5+5;

int f[N];

int getf(int x,int &s)
{
    if(x!=f[x])
    {
        s++;
        f[x]=getf( f[x],s); //画图,压缩路径,加起来 
    }
    return f[x];
}
int main()
{
    int n,k, a,b,v,fa,fb,q;
    int ans=0;
    while(cin>>n && n)
    {
        for(int i=0;i<=n;i++) f[i]=i;
        int flag=0;
        
        cin>>k;
        while(k--)
        {
            scanf("%d%d",&a,&b);
            if(flag==1) continue;
            int sa=0,sb=0;
            fa=getf(a,sa);
            fb=getf(b,sb);
            if(fa==fb){
                if( (sa+sb+1)%2==1) //奇数环 
                {
                    flag=1; 
                    continue;
                }
            }
            else
            {
                f[fa]=fb; 
            }
        }
        if(flag)
            cout<<"NOT BICOLORABLE."<<endl;
        else
            cout<<"BICOLORABLE."<<endl;
    } 
}
View Code

猜你喜欢

转载自www.cnblogs.com/thunder-110/p/10322669.html