【题解】HNOI-2010 Planar

Problem

bzoj
洛谷

题意:给定一张完全图和图中的一条哈密顿回路,问是否为平面图

Solution

看到这题中有一条哈密顿回路,如果这个图是平面图,那么这条哈密顿回路在平面上就是一个切割平面的圈

明显想到每一条非哈密顿回路上的边不会和这个圈相交,则一定在这个圈的外部或内部

发现如果将两条边放在圈的同一侧必定相交,那么就必须把它俩分开(一条在里面一条在外面),那么对每两条边来说有可能有上述限制条件,最后看所有条件是否会冲突

判断冲突的方法比较多,一般根据冲突建图,然后tarjan、变种匈牙利、并查集随便搞,不建图也能用搜索水过

发现这样的话,枚举每两条边考虑限制条件是 O ( m 2 ) 的,然而 m 10000 , T 100 使得我们不得不优化这个复杂度

数学知识:一个有 n 个点的平面图上最多有 n 3 6 条边(在数学组小蓝皮上有很多比较有用的平面图知识)

据此可以将边数大于 n 3 6 的情况预判掉,剩下的情况中边数与点数是同一个量级 200

蒟蒻用的是并查集

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rg register
#define cl(x) memset(x,0,sizeof(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)>0?(x):(-(x)))

template <typename _Tp> inline _Tp read(_Tp&x){
    rg char c11=getchar(),ob=0;x=0;
    while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')c11=getchar(),ob=1;
    while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return x;
}

const int N=205,M=10500;
int dad[M],d[M],l[M],r[M],cannot[M];
int n,m;

inline int father(int x){return dad[x]?dad[x]=father(dad[x]):x;}

int main(){
    int T;read(T);while(T--){
        read(n);read(m);
        if(3*n+6<m){
            for(rg int i=1,x;i<=m;++i)read(x),read(x);
            for(rg int i=1,x;i<=n;++i)read(x);
            puts("NO");continue;
        }cl(dad);cl(cannot);
        for(rg int i=1;i<=m;++i)read(l[i]),read(r[i]);
        for(rg int i=1,x;i<=n;++i)d[read(x)]=i;
        for(rg int i=1;i<=m;++i){
            l[i]=d[l[i]],r[i]=d[r[i]];
            if(l[i]>r[i])swap(l[i],r[i]);
            if(l[i]+1==r[i]||(l[i]==1&&r[i]==n))cannot[i]=1;
        }
        int p1,p2;
        for(rg int i=1;i<=m;++i)if(!cannot[i])
        for(rg int j=i+1;j<=m;++j)if(!cannot[j])
            if( (l[i]<l[j] && l[j]<r[i] && r[i]<r[j]) || (l[j]<l[i] && l[i]<r[j] && r[j]<r[i]) )
            if( l[i]!=l[j] && r[i]!=r[j] && l[i]!=r[j] && r[i]!=l[j] ){
                if(father(i)==father(j))goto end;
                if((p1=father(i))!=(p2=father(j+m))) dad[p1]=p2;
                if((p1=father(j))!=(p2=father(i+m))) dad[p1]=p2;
            }
        for(rg int i=1;i<=m;++i)if(father(i)==father(i+m))goto end;
        puts("YES");continue;
        end : puts("NO");
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40515553/article/details/79859163
今日推荐