[HNOI2010] 平面图判定 planar
标签:二分图判定。
题解:
首先可以把题目中给你的那个环给画出来,这样就可以发现对于任意一个图来说,如果两条边要相交,就不能让他们相交,那么这两条边就要一条在里面一条在外面,如果把环画成一条链,那么就是一条在下面,一条在上面。于是我们想到对于边,O(n2)的枚举,判断是否相交即可,如果相交的话,就要连一条边,到时候判断这一个图(把原图边看成新图的点)是不是二分图即可,简单的二分图染色判定即可。
当然了O(n2)对于10000条边来说,因为有多组数据,会被卡掉,那么我们就要想办法,点这么少,边这么多,那么最多能有多少条边而且这个图是平面图呢?通过手玩找规律,先画出一条环,有n条边,然后这个环的一个点向非相邻的n-3个点连接n-3条边可以保证两两不相交,外面一侧如此,故如果边数m>n*3-6,就直接判断NO即可。保证了复杂度。
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAXN=205,MAXM=605; int Case,n,m; int F[15000],T[15000],rk[MAXN],con[MAXM][MAXM],color[MAXM]; inline int gi(){int res; scanf("%d",&res); return res;} bool judge(int S) { queue<int>Q; color[S]=1; Q.push(S); while(!Q.empty()) { int u=Q.front(); Q.pop(); for(int i=1;i<=m;i++) if(con[u][i]) { if(color[i]==-1) { color[i]=!color[u]; Q.push(i); } else if(color[i]==color[u]) return 0; } } return 1; } int main() { Case=gi(); while(Case--) { n=gi(); m=gi(); for(int i=1;i<=m;i++) { F[i]=gi(); T[i]=gi(); } for(int i=1;i<=n;i++) rk[gi()]=i; if(m>n*3-6){puts("NO");continue;} memset(con,0,sizeof con); memset(color,-1,sizeof color); for(int i=1,A,B,C,D;i<m;i++) for(int j=i+1;j<=m;j++) { A=rk[F[i]],B=rk[T[i]]; C=rk[F[j]],D=rk[T[j]]; if(A>B)swap(A,B); if(C>D)swap(C,D); if((B>C && B<D && C>A) || (D>A && D<B && A>C)) con[i][j]=con[j][i]=1; } bool flag=0; for(int i=1;i<=m;i++) if(color[i]==-1 && !judge(i)) { flag=1; break; } if(flag)puts("NO"); else puts("YES"); } return 0; }