【问题描述】
若能将无向图 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;
}