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;
    } 
}
并查集

 

#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 n,m;
int e[205][205] ;
int book[N]; //用来标记每个顶点的颜色,即如果a b相连,顶点a 颜色为-1,
             //那么b的颜色 一定要为1 (只有1,-1这两种颜色 ),否则就不满足 

int bfs()
{
    queue<int>q;
    q.push(0);  //应该题目 输入的全部数据一定有0顶点。 
    book[0]=-1;
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        for(int i=0;i<=n;i++)
        {
            if(e[t][i]) //顶点t到顶点i有边 
            {
                if(book[i]) //i已经被遍历过
                {
                    if(book[t]==book[i])  
                        return 1;
                } 
                else
                {
                    book[i]= -book[t];
                    q.push(i);
                }
            }
        } 
    }
    return 0;
}
int main()
{
    while(cin>>n && n)
    {
        mem(e,0);
        mem(book,0);
        cin>>m;
        for(int i=1;i<=m;i++)
        {
            int xx, yy;
            scanf("%d%d",&xx,&yy);
            e[xx][yy]=e[yy][xx]=1 ;
        }
        if(bfs())
            cout<<"NOT BICOLORABLE."<<endl;
        else
            cout<<"BICOLORABLE."<<endl;
    } 
}
bfs搜索

 

posted @ 2019-01-26 10:05  木流牛马  阅读(492)  评论(1编辑  收藏  举报