zoukankan      html  css  js  c++  java
  • HNOI2010 平面图判定

    对于这个题,我们只需要判断是否为平面图。

    我们发现他给了我们一个很好的性质:那就是这个平面图上存在着一个哈密顿回路(n元环)。

    那么我们就可以很简单的判定两条边 如果划在同一侧是否会相交。

    如果相交,那么我们就得把他们放在两侧,否则不需要。

    然后只需判断是否在满足所有条件的前提下出现了矛盾就行了。

    要解决这个东西,并查集很擅长,但是这里用建图缩点解决。

    对于一条边i,只有可能里外两侧,分别记为di,di'。

    那么对于两条需要异侧的边i,j,我们只需连上无向边(di, dj'),(dj, di')。

    然后我们可以对于每一个需要满足的条件,建出一个图,

    缩点后,如果同一个强连通分量中存在di,di'那么就不是。

    最后最好加上一条平面图的性质优化一下。

    就是平面图的 边数不超过点数*3-6。

    #include <string>
    #include <cstdio>
    #include <cstring>
    #define RG register
    #define Swap(a,b) a^=b,b^=a,a^=b
    using namespace std;
    
    inline int gi () {
        int x=0,w=0; char ch=0;
        while (ch<'0' || ch>'9') {if (ch=='-') w=1; ch=getchar ();}
        while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48), ch=getchar ();
        return w?-x:x;
    }
    
    const int N=410;
    const int M=1e5+10;
    
    int tot,head[M<<1],to[M<<2],Next[M<<2];
    int T,n,m,num,u[M],v[M],Ex[M],Ey[M],a[N][N],pos[M];
    int Time,cnt,top,ins[M<<1],dfn[M<<1],low[M<<1],sta[M<<1],Bel[M<<1];
    
    inline void New_case () {
        Time=tot=cnt=top=num=0;
        memset (a, 0, sizeof (a));
        memset (pos, 0, sizeof (pos));
        memset (ins, 0, sizeof (ins));
        memset (dfn, 0, sizeof (dfn));
        memset (low, 0, sizeof (low));
        memset (Bel, 0, sizeof (Bel));
        memset (head, 0, sizeof (head));
        memset (to, 0, sizeof (to));
        memset (Next, 0, sizeof (Next));
    }
    
    inline void make (int from, int To) {
        Next[++tot]=head[from];
        head[from]=tot;
        to[tot]=To;
    }
    
    inline bool cross (int a, int b) {
        RG int fr1=pos[Ex[a]],fr2=pos[Ex[b]],tt1=pos[Ey[a]],tt2=pos[Ey[b]];
        if (fr1>tt1) Swap (fr1, tt1); if (fr2>tt2) Swap (fr2, tt2);
        if (fr1<fr2 && tt1<tt2 && tt1>fr2) return 1;
        if (fr1>fr2 && tt1>tt2 && tt2>fr1) return 1;
        return 0;
    }
    
    void Tarjan (int x) {
        dfn[x]=low[x]=++Time;
        sta[++top]=x, ins[x]=1;
        for (RG int i=head[x],y;i;i=Next[i]) {
            y=to[i];
            if (!dfn[y]) Tarjan (y), low[x]=min (low[x], low[y]);
            else if (ins[y]) low[x]=min (low[x], dfn[y]);
        }
        if (low[x]==dfn[x]) {
            ++cnt;
            RG int k;
            do {
                k=sta[top--], ins[k]=0, Bel[k]=cnt;
            }while (k!=x);
        }
    }
    
    inline bool check () {
        for (RG int i=1;i<=num;++i)
            if (Bel[i]==Bel[i+m]) return 0;
        return 1;
    }
    
    int main ()
    {
        RG int i,j,fir,x,y;
        T=gi ();
        while (T--) {
            New_case ();
            n=gi (), m=gi ();
            for (i=1;i<=m;++i) u[i]=gi (), v[i]=gi ();
            x=fir=gi (), pos[x]=1;
            for (i=2;i<=n;++i) y=gi (), pos[y]=i, a[x][y]=a[y][x]=1, x=y;
            a[fir][x]=a[x][fir]=1;
            if (m>3*n-6) {
                puts ("NO");
                continue;
            }
            for (i=1;i<=m;++i)
                if (!a[u[i]][v[i]]) Ex[++num]=u[i], Ey[num]=v[i];
            for (i=1;i<=num;++i)
                for (j=i+1;j<=num;++j)
                    if (cross (i,j))
                        make (i, j+m), make (j+m, i), make (j, i+m), make (i+m, j);
            for (i=1;i<=num+m;++i)
                if (!dfn[i]) Tarjan (i);
            check ()?puts ("YES"):puts ("NO");
        }
        return 0;
    }
  • 相关阅读:
    数据库常见操作三
    数据库常见操作二
    readelf源码学习
    c++ 常用排序
    分析笔记-反编译失败的锁机apk简单分析
    低自尊者
    Microstation软件操作学习2
    Bentley MicroStation版本号
    Microstation软件操作学习1
    MSCEC#创建工程
  • 原文地址:https://www.cnblogs.com/Bhllx/p/9864999.html
Copyright © 2011-2022 走看看