题目描述
若能将无向图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。输入的数据保证100%的数据满足T<=100,3<=N<=200,M<=10000。
输出格式:
包含T行,若输入文件的第i组数据所对应图是平面图,则在第i行输出YES,否则在第i行输出NO,注意均为大写字母
思路
先用平面图定理 m<=3*n+6 把边数减小到O(n)级别。
然后设 集合 i+m 表示 不能与i共存的边 所在的集合。
枚举每一对不能共存的边,如果已经在同一个集合内,则无解。
否则交叉连边 fa[find(i)]=j+m , fa[find(j)]=i+m 。
如何判断两条边是否相交?先把所有边坐标转换为哈密顿回路中的顺序坐标,对于任意两条边i,j,如果有xi
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2e3+1e1;
int x[maxn<<4],y[maxn<<4],vis[maxn<<4];
int id[maxn];
int fa[maxn<<5];
int T,n,m;
inline int findfa(int x)
{
return fa[x] == x ? x : fa[x] = findfa(fa[x]);
}
inline void initfa()
{
for(int i=1;i<=m<<1;i++)
fa[i] = i;
}
inline bool cross(int x1,int x2,int y1,int y2)
{
if( x1 == x2 || y1 == y2 || x1 == y2 || x2 == y1 )
return 0;
if( x1 < x2 && y1 < y2 && x2 < y1 )
return 1;
if( x2 < x1 && y2 < y1 && x1 < y2 )
return 1;
return 0;
}
inline bool check()
{
initfa();
for(int i=1;i<=m;i++)
{
if( vis[i] )
continue;
for(int j=1;j<=m;j++)
{
if( vis[j] )
continue;
if( !cross(x[i],x[j],y[i],y[j]) )
continue;
int fai = findfa(i) , faj = findfa(j);
if( fai == faj )
return 0;
fa[fai] = findfa( j + m ),
fa[faj] = findfa( i + m );
}
}
return 1;
}
inline void init()
{
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(vis,0,sizeof(vis));
n = m = 0;
}
inline int getint()
{
int ret = 0;
char ch = getchar();
while( ch < '0' || ch > '9' )
ch = getchar();
while( '0' <= ch && ch <= '9' )
ret = ret * 10 + ( ch - '0' ),
ch = getchar();
return ret;
}
int main()
{
T = getint();
while( T-- )
{
init();
n = getint() , m = getint();
for(int i=1;i<=m;i++)
x[i] = getint() , y[i] = getint();
for(int i=1;i<=n;i++)
id[getint()] = i;
if( m > 3 * n + 6 )
{
puts("NO");
continue;
}
for(int i=1,a,b;i<=m;i++)
{
a = id[x[i]] , b = id[y[i]];
x[i] = min( a , b ),
y[i] = max( a , b );
}
for(int i=1;i<=m;i++)
if( y[i] == x[i] + 1 || ( y[i]==n && x[i]==0) )
vis[i] = 1;
if( check() )
puts("YES");
else puts("NO");
}
return 0;
}