zoukankan      html  css  js  c++  java
  • 洛谷P3209 [HNOI2010]PLANAR(2-SAT)

    题目描述

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

    输入输出格式

    输入格式:

    输入文件的第一行是一个正整数T,表示数据组数(每组数据描述一个需要判定的图)。接下来从输入文件第二行开始有T组数据,每组数据的第一行是用空格隔开的两个正整数N和M,分别表示对应图的顶点数和边数。紧接着的M行,每行是用空格隔开的两个正整数u和v(1<=u,v<=n),表示对应图的一条边(u,v),输入的数据保证所有边仅出现一次。每组数据的最后一行是用空格隔开的N个正整数,从左到右表示对应图中的一个哈密顿回路:V1,V2,…,VN,即对任意i≠j有Vi≠Vj且对任意1<=i<=n-1有(Vi,Vi-1) ∈E及(V1,Vn) ∈E。输入的数据保证100%的数据满足T<=100,3<=N<=200,M<=10000。

    输出格式:

    包含T行,若输入文件的第i组数据所对应图是平面图,则在第i行输出YES,否则在第i行输出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

    说明

    感谢@hibiki 对题目进行修正

    如果你会做POJ3207的话,那么这道题就是道大水题

    不过平面图有一个性质

    边数$<=$点数$*3-6$

    因此可以通过这个性质把数据规模降至$O(n)$

    设$i$表示边$i$在圆内,$i'$表示$i$在圆外

    若$(i,j)$在圆内相交,那么它们在圆外也一定相交

    如果边$i,j$在圆内相交

    那么就从$i$连向$j'$(i内j外),从$j'$连向$i$(i内j外),从$j$连向$i'$(j内i外),从$i'$连向$j$(j内i外)

    写错了一个字母调了半个小时

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    #include<vector>
    #include<queue>
    #include<iostream>
    #define Pair pair<int,int>
    #define F first
    #define S second
    using namespace std;
    const int MAXN=1e6+10;
    //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
    char buf[1<<20],*p1=buf,*p2=buf;
    inline int read()
    {    char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    struct node
    {
        int u,v,nxt;
    }edge[MAXN];
    int head[MAXN],num=1;
    inline void AddEdge(int x,int y)
    {
        edge[num].u=x;
        edge[num].v=y;
        edge[num].nxt=head[x];
        head[x]=num++;
    }
    int happen[MAXN];
    int dfn[MAXN],low[MAXN],tot,color[MAXN],colornum=0,vis[MAXN];
    stack<int>s;
    int N,M;
    Pair P[MAXN];
    void tarjan(int now)
    {
        dfn[now]=low[now]=++tot;
        s.push(now);
        vis[now]=1;
        for(int i=head[now];i!=-1;i=edge[i].nxt)
        {
            if(!dfn[edge[i].v])
                tarjan(edge[i].v),low[now]=min(low[now],low[edge[i].v]);
            else if(vis[edge[i].v]) low[now]=min(low[now],dfn[edge[i].v]);
        }
        if(dfn[now]==low[now])
        {
            int h;colornum++;
            do
            {
                h=s.top();s.pop();
                vis[h]=0;
                color[h]=colornum;
            }while(h!=now);
        }
    }
    void pre()
    {
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(head,-1,sizeof(head));
        memset(color,0,sizeof(color));
        memset(happen,0,sizeof(happen));
        memset(vis,0,sizeof(vis));
        num=1;
    }
    int main()
    {
        #ifdef WIN32
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        #else
        #endif
        int QWQ=read();
        while(QWQ--)
        {
            pre();
            N=read();M=read();
            for(int i=1;i<=M;i++)
                P[i].F=read(),P[i].S=read();
            for(int i=1;i<=N;i++)
            {
                int p=read();
                happen[p]=i;
            }
            if(M>3*N-6){printf("NO
    "); continue;}
            for(int i=1;i<=M;i++)
            {
                P[i].F=happen[P[i].F];
                P[i].S=happen[P[i].S];
                if(P[i].F>P[i].S) swap(P[i].F,P[i].S);
            }
            for(int i=1;i<=M;i++)
                for(int j=i+1;j<=M;j++)
                    if((P[i].S>P[j].F&&P[i].F<P[j].F&&P[i].S<P[j].S)
                     ||(P[i].F>P[j].F&&P[i].S>P[j].S&&P[i].F<P[j].S))
                         AddEdge(i,j+M),
                         AddEdge(j+M,i),
                         AddEdge(j,i+M),
                         AddEdge(i+M,j);
            for(int i=1;i<=2*M;i++)
                if(!dfn[i])
                    tarjan(i);
            int flag=1;
            for(int i=1;i<=2*M;i++)
                if(color[i]==color[i+M])
                    {printf("NO
    ");flag=0;break;}
            if(flag==1) printf("YES
    ");    
        }
        return 0;
    }
  • 相关阅读:
    EP-N8530S USB WIFI 驱动移植
    MySQL(十三)事务处理和字符集
    MySQL(十二)游标和触发器
    《Google软件测试之道》测试工程师
    jmeter(十二)关联之正则表达式提取器
    MySQL(十一)视图及存储过程
    jmeter(十一)JDBC Request之Query Type
    MySQL(十)操纵表及全文本搜索
    MySQL(九)插入、更新和删除
    MySQL(八)子查询和分组查询
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/8485294.html
Copyright © 2011-2022 走看看