zoukankan      html  css  js  c++  java
  • Luogu P3209 [HNOI2010]平面图判定(2-SAT)

    P3209 [HNOI2010]平面图判定

    题意

    题目描述

    若能将无向图(G=(V,E))画在平面上使得任意两条无重合顶点的边不相交,则称(G)是平面图。判定一个图是否为平面图的问题是图论中的一个重要问题。现在假设你要判定的是一类特殊的图,图中存在一个包含所有顶点的环,即存在哈密顿回路。

    输入输出格式

    输入格式:

    输入文件的第一行是一个正整数(T),表示数据组数 (每组数据描述一个需要判定的图)。接下来从输入文件第二行开始有(T)组数据,每组数据的第一行是用空格隔开的两个正整数(N)(M),分别表示对应图的顶点数和边数。紧接着的(M)行,每行是用空格隔开的两个正整数(u)(vleft(1leq u,vleq N ight)),表示对应图的一条边(left(u,v ight)), 输入的数据保证所有边仅出现一次。每组数据的最后一行是用空格隔开的(N)个正整数,从左到右表示对应图中的一个哈密顿回路(V_1,V_2,dots ,V_N),即对任意(i ot=j)(V_i ot=V_j)且对任意(1leq ileq N-1)(left(V_i,V_i-1 ight)in E)(left(V_1,V_N ight)in E)。输入的数据保证(100\%)的数据满足(Tleq100,3leq Nleq200,Mleq1000)

    输出格式:

    包含(T)行,若输入文件的第(i)组数据所对应图是平面图,则在第(i)行输出 ( ext{YES}),否则在第(i)行输出( ext{NO}),注意均为大写字母。

    输入输出样例

    输入样例#1:

    2
    6 9
    1 4
    1 5
    1 6
    2 4
    2 5
    2 6
    3 4
    3 5
    3 6
    1 4 2 5 3 6
    5 5
    1 2
    2 3
    3 4
    4 5
    5 1
    1 2 3 4 5
    

    输出样例#1:

    NO
    YES
    

    思路

    这题毒瘤,要先转对偶图... --huyufeifei

    其实这题也没那么毒瘤,直接(2-SAT)或者并查集就好了。

    我们先把哈密顿回路搬出来,画成一个圆,再来考虑图上其他的边。其他的边有两种画法:画在圆内,画在圆外。有些边,如果都画在圆内,就会相交,不符合平面图的性质;而如果他们都画在圆外,也会相交。所以我们可以把边拿出来,把其是否画在圆内作为这条边的边权,两条边不可相交作为其限制条件,做(2-SAT)就好了。当然,(alec)神仙写的是并查集做法,也是十分可行的。

    还有一个剪枝:显然平面图中的边的数量不能太多,因为图越稠密越难画出平面图,所以当当前状况下边数过多时,我们就可以直接判NO。上网查资料得(mleq 3n-2)(这个是可以用欧拉公式证明的。 --logeadd),加上剪枝就能跑得很快了。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=205;
    const int MAXM=605;
    int T,n,m,id[MAXN],inv[MAXN],u[10005],v[10005];
    int nn,U[MAXM],V[MAXM];
    int cnt,top[MAXM<<1],to[(MAXM*MAXM)<<2],nex[(MAXM*MAXM)<<2];
    int tot,js,dfn[MAXM<<1],low[MAXM<<1],bel[MAXM<<1];
    bool cir[MAXN][MAXN],vis[MAXM<<1];
    stack<int>S;
    int read()
    {
        int re=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
        return re;
    }
    void add_edge(int x,int y){to[++cnt]=y,nex[cnt]=top[x],top[x]=cnt;}
    void tarjan(int now)
    {
        dfn[now]=low[now]=++tot,vis[now]=true,S.push(now);
        for(int i=top[now];i;i=nex[i])
            if(!dfn[to[i]]) tarjan(to[i]),low[now]=min(low[now],low[to[i]]);
            else if(vis[to[i]]) low[now]=min(low[now],low[to[i]]);
        if(dfn[now]==low[now])
        {
            bel[now]=++js,vis[now]=false;
            while(S.top()!=now) bel[S.top()]=js,vis[S.top()]=false,S.pop();
            S.pop();
        }
    }
    int main()
    {
        T=read();
        while(T--)
        {
            n=read(),m=read(),nn=cnt=tot=js=0;
            memset(id,0,sizeof id);
            memset(inv,0,sizeof inv);
            memset(u,0,sizeof u);
            memset(v,0,sizeof v);
            memset(U,0,sizeof U);
            memset(V,0,sizeof V);
            memset(top,0,sizeof top);
            memset(dfn,0,sizeof dfn);
            memset(low,0,sizeof low);
            memset(bel,0,sizeof bel);
            memset(cir,false,sizeof cir);
            for(int i=1;i<=m;i++)
            {
                int x=read(),y=read();
                if(x>y) swap(x,y);
                u[i]=x,v[i]=y;
            }
            for(int i=1;i<=n;i++)
            {
                int x=read();
                id[x]=i,inv[i]=x;
                if(i!=1)
                {
                    int y=inv[i-1];
                    if(x>y) swap(x,y);
                    cir[x][y]=true;
                }
            }
            if(m>3*n-6)
            {
                puts("NO");
                continue;
            }
            if(inv[1]<inv[n]) cir[inv[1]][inv[n]]=true;
            else cir[inv[n]][inv[1]]=true;
            for(int i=1;i<=m;i++) if(!cir[u[i]][v[i]]) U[++nn]=u[i],V[nn]=v[i];
            for(int i=1;i<=nn;i++)
                for(int j=i+1;j<=nn;j++)
                {
                    int x=id[U[i]],y=id[V[i]],xx=id[U[j]],yy=id[V[j]];
                    if(x>y) swap(x,y);
                    if(xx>yy) swap(xx,yy);
                    if((x<xx&&xx<y&&y<yy)||(xx<x&&x<yy&&yy<y)) add_edge(i,j+nn),add_edge(i+nn,j),add_edge(j,i+nn),add_edge(j+nn,i);
                }
            for(int i=1;i<=(nn<<1);i++) if(!dfn[i]) tarjan(i);
            bool ans=true;
            for(int i=1;i<=nn;i++)
                if(bel[i]==bel[i+nn])
                {
                    ans=false;
                    break;
                }
            if(ans) puts("YES");
            else puts("NO");
        }
        return 0;
    }
    
  • 相关阅读:
    服务命令Linux安装配置apache
    枚举参考hdu2062Subset sequence
    异常选择struts2文件上传产生Source 'xxxx.tmp' does not exist
    序列插入常用排序算法 总结
    代码nullMerge two sorted linked lists
    下载文件win8mp3下载
    希望判断创造、改变世界的基因
    qemulauncher:图形化的QEMU启动器
    Virtual Memory I: the problem
    HIGHMEM
  • 原文地址:https://www.cnblogs.com/coder-Uranus/p/9894044.html
Copyright © 2011-2022 走看看