hnoi2010 平面图判定 2_SAT

来源:互联网 发布:加好友的软件 编辑:程序博客网 时间:2024/06/11 13:38

【问题描述】

  若能将无向图 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。

【输出格式】

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

【输入样例】

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

【输出样例】

NO
YES

【数据范围】

保证100%的数据满足T≤100,3≤N≤200,M≤10000

————————————————————————————————————————————————————————

区分这是水题还是难题的唯一一个地方就是。。。。。
你有没有发现实际上这个边是可以绕到外面去的ORZ

开始脑补了一个并查集的算法发现有反例就上2_ SAT了,一条边只能在里面或者外面,然后和它可能有交点的边都是不能和它在同一侧的,所以就可以用2_SAT来判定了。把边当成点,然后拆成2个表示在里面和在外面。
可以发现一件事情,如果边只能走里面的话这个时候最极限的情况就是三角形剖分,这个时候一共有N*2-3条边。边走外面同理,就是把里面的翻过来而已。所以说在M>N *3-6的时候就可以直接判定为无解。
建图转化为线段相交问题,两个线段互相包含不会有交点,相交不包含才会有交点。
所以说总时间复杂度为O(T*N^3)。

AC代码:

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>#include<queue>#include<set>#include<map>#include<vector>#include<cctype>using namespace std;const int maxn=205;const int maxm=10005;int T,N,M,A[maxn],id[maxn];struct edges{ int from,to; }_E[maxm];struct edge{ int to,next; }E[maxn*maxn*18];int first[maxm<<1],np,other[maxm<<1],stk[maxm<<1],top;bool vis[maxm<<1];void _scanf(int &x){    x=0;    char ch=getchar();    while(ch<'0'||ch>'9') ch=getchar();    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();}void add_edge(int u,int v){    E[++np]=(edge){v,first[u]};    first[u]=np;}void data_in(){    memset(first,0,sizeof(first));    np=0;    _scanf(N);_scanf(M);    int x,y;    for(int i=1;i<=M;i++)    {        _scanf(x);_scanf(y);        _E[i]=(edges){x,y};        other[i]=i+M,other[i+M]=i;    }    for(int i=1;i<=N;i++) _scanf(A[i]),id[A[i]]=i;    if(M>N*3-6) return;    for(int i=1;i<M;i++)    for(int j=i+1;j<=M;j++)    {        int a=id[_E[i].from],b=id[_E[i].to];        int c=id[_E[j].from],d=id[_E[j].to];        if(a>b) swap(a,b);        if(c>d) swap(c,d);        if(a<c&&c<b&&b<d||c<a&&a<d&&d<b)        {            add_edge(i,other[j]);            add_edge(j,other[i]);            add_edge(other[i],j);            add_edge(other[j],i);        }    }}bool DFS(int i){    vis[i]=1;    for(int p=first[i];p;p=E[p].next)    {        int j=E[p].to;        if(vis[j]) continue;        if(vis[other[j]]) return 0;        if(!DFS(j)) return 0;    }    return 1;}bool two_SAT(){    memset(vis,0,sizeof(vis));    for(int i=1;i<=M;i++)    {        if(vis[i]||vis[other[i]]) continue;        top=0;        if(!DFS(i))        {            while(top) vis[stk[top--]]=0;            if(!DFS(other[i])) return 0;        }    }    return 1;}void work(){    if(M<=N*3-6&&two_SAT()) printf("YES\n");    else printf("NO\n");}int main(){    freopen("test.in","r",stdin);    freopen("test.out","w",stdout);    _scanf(T);    for(int i=1;i<=T;i++)    {        data_in();        work();    }    return 0;}