BZOJ1997: [Hnoi2010]Planar(洛谷P3209)

2-SAT 平面图

BZOJ题目传送门
洛谷题目传送门

首先根据平面图的性质,如果 m>n36 ,那么这个图一定不是平面图。这样我们就可以把边数缩至 n 级别的了。

因为存在哈密顿回路,那么对于连接相同的两点的边,最多只能有两条(除了哈密顿回路的边),一条在环的里面,一条在环的外面。这样的限制满足2-SAT.

用手画几张图就可以发现,当两条边相交时,必然都在环的同一侧。记相交的边 i 连接的两点为 u v u<v ),边 j 连接的两点为 x y x<y ),可以发现 u<x<v<y x<u<y<v 。因此当上述关系出现时,建边 <i,j xor 1> (选了i的这侧必须选j的另一侧,下同)、 <j,i xor 1> 以及它们的反边。缩点后判 i i xor 1 是否在同一个联通块即可。

代码:

#include
#include
#include
#include
#define N 205
#define M 10005
#define K ((N*3-6)<<1)
using namespace std;
struct edge1{ int x,y; }edg[N<<1];
struct edge2{ int next,to; }ed[K*K<<2];
int n,m,t,tp,nd,s,p,k,h[K],c[N],e[M][2],hs[N];
int low[K],dfn[K],stk[K],num[K];
bool f[K],exst[N][N];
inline char readc(){
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF; return *l++;
}
inline int _read(){
    int x=0; char ch=readc();
    while (!isdigit(ch)) ch=readc();
    while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
    return x;
}
inline void addedge(int x,int y){ 
    ed[++k].next=h[x],ed[k].to=y,h[x]=k;
}
void Tarjan(int x){
    low[x]=dfn[x]=++p,stk[++tp]=x,f[x]=true;
    for (int i=h[x],v=ed[i].to;i;i=ed[i].next,v=ed[i].to)
        if (!dfn[v]) Tarjan(v),low[x]=min(low[x],low[v]);
        else if (f[v]) low[x]=min(low[x],dfn[v]);
    if (low[x]==dfn[x]){
        f[x]=false,num[x]=++nd; int y;
        do y=stk[tp--],f[y]=false,num[y]=nd; while (y!=x);
    }
}
int main(){
    t=_read();
    while (t--){
        memset(h,0,sizeof(h));
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        memset(num,0,sizeof(num));
        memset(exst,false,sizeof(exst));
        n=_read(),m=_read(); s=k=p=nd=0;
        for (int i=1;i<=m;i++){
            e[i][0]=_read(),e[i][1]=_read();
            if (e[i][0]>e[i][1]) swap(e[i][0],e[i][1]);
        }
        for (int i=1;i<=n;i++){
            hs[c[i]=_read()]=i;
            if (i!=1) exst[min(c[i],c[i-1])][max(c[i],c[i-1])]=true;
        }
        if (m>n*3-6) { printf("NO\n"); continue; }
        exst[min(c[1],c[n])][max(c[1],c[n])]=true;
        for (int i=1;i<=m;i++){//要把在哈密顿回路上的边去掉
            if (exst[e[i][0]][e[i][1]]) continue;
            edg[s].x=e[i][0],edg[s].y=e[i][1],s+=2;
        }
        for (int i=0;i2;i+=2)
            for (int j=i+2;j2){
                int u=hs[edg[i].x],v=hs[edg[i].y],x=hs[edg[j].x],y=hs[edg[j].y];
                if (u>v) swap(u,v); if (x>y) swap(x,y);
                if ((ux&&vu&&y1),addedge(j,i^1);
                    addedge(j^1,i),addedge(i^1,j);
                }
            }
        bool flag=false;
        for (int i=0;i<(s<<1);i++) if (!dfn[i]) Tarjan(i);
        for (int i=0;i<(s<<1);i+=2) if (num[i]==num[i^1]) { flag=true; break; }
        if (flag) printf("NO\n"); else printf("YES\n");
    }
    return 0;
}

你可能感兴趣的:(洛谷,BZOJ,图论---2-SAT,蒟蒻zxl的Blog专栏,平面图,2-SAT,BZOJ,洛谷)