Problem
题意:给定一张完全图和图中的一条哈密顿回路,问是否为平面图
Solution
看到这题中有一条哈密顿回路,如果这个图是平面图,那么这条哈密顿回路在平面上就是一个切割平面的圈
明显想到每一条非哈密顿回路上的边不会和这个圈相交,则一定在这个圈的外部或内部
发现如果将两条边放在圈的同一侧必定相交,那么就必须把它俩分开(一条在里面一条在外面),那么对每两条边来说有可能有上述限制条件,最后看所有条件是否会冲突
判断冲突的方法比较多,一般根据冲突建图,然后tarjan、变种匈牙利、并查集随便搞,不建图也能用搜索水过
发现这样的话,枚举每两条边考虑限制条件是 O(m2) O ( m 2 ) 的,然而 m≤10000,T≤100 m ≤ 10000 , T ≤ 100 使得我们不得不优化这个复杂度
数学知识:一个有 n n 个点的平面图上最多有条边(在数学组小蓝皮上有很多比较有用的平面图知识)
据此可以将边数大于 n∗3−6 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");
}
}