【题解】HNOI-2010 Planar

Problem

bzoj
洛谷

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

Solution

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

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

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

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

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

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

据此可以将边数大于 n36 n ∗ 3 − 6 的情况预判掉,剩下的情况中边数与点数是同一个量级 200 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");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值