hnoi2010 平面图判定 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。

【输出格式】

  包含 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;ifor(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(abool 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;
}

你可能感兴趣的:(2-SAT)