1997: [Hnoi2010]Planar 二分图染色

并不会做。。于是看了题解。
看完铺天盖地的2-SAT题解后,我似乎明白了怎么用二分图染色做。(好神奇的一句话- -)
虽然我并不知道2-SAT是什么。。但似乎和二分图染色是一个差不多的东西,都是维护边之间的关系。
比如这个题,所有的点在一个环上,所以点之间的边在环内或者环外,如果两条边在环内相交,那么它们对应在环外也相交。且同一条边只能在内或者在外不可能两条边同时有。
有了这些限制关系,我们就可以建图连边了,如果能进行二分图染色,那么就是一个合法的平面图,否则不是。

#include<iostream> 
#include<cstdio>
#include<cstring>
using namespace std;
int u[10005],v[10005],head[2005],pos[2005],col[2005];
int next[1000005],list[1000005];
int n,m,T,tot,cnt,flag;
inline int read()
{
    int a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
inline void insert(int x,int y)
{
    next[++cnt]=head[x];
    head[x]=cnt;
    list[cnt]=y;
}
bool color(int x,int c)
{
    col[x]=c;
    for (int i=head[x];i;i=next[i])
    {
        if (col[list[i]]==col[x]) return 0;
        if (col[list[i]]==-1) if (!color(list[i],c^1)) return 0;
    }
    return 1;
}
int main()
{
    T=read();
    while (T--)
    {
        memset(head,0,sizeof(head));
        memset(col,-1,sizeof(col));
        tot=cnt=flag=0;
        n=read(); m=read();
        for (int i=1;i<=m;i++) u[i]=read(),v[i]=read();
        for (int i=1,x;i<=n;i++) x=read(),pos[x]=i;
        if (m>3*n-6) {puts("NO"); continue;}
        for (int i=1;i<=m;i++)
        {
            u[i]=pos[u[i]]; v[i]=pos[v[i]];
            if (u[i]>v[i]) swap(u[i],v[i]);
            if (v[i]-u[i]==1||v[i]-u[i]==n-1) continue;
            u[++tot]=u[i]; v[tot]=v[i];
        }
        for (int i=1;i<=tot;i++)
            for (int j=i+1;j<=tot;j++)
                if ((u[i]<u[j]&&u[j]<v[i]&&v[i]<v[j])||(u[j]<u[i]&&u[i]<v[j]&&v[j]<v[i]))
                    insert(2*i,2*j),insert(2*j,2*i),insert(2*i+1,2*j+1),insert(2*j+1,2*i+1);
        for (int i=1;i<=tot;i++) insert(2*i,2*i+1),insert(2*i+1,2*i);
        for (int i=1;i<=2*tot;i++)
            if (col[i]==-1) if (!color(i,1)) {flag=1; break;}
        flag?puts("NO"):puts("YES");
    }
    return 0;
}       

你可能感兴趣的:(1997: [Hnoi2010]Planar 二分图染色)