1. 程式人生 > >[HNOI2010] 平面圖判定 planar

[HNOI2010] 平面圖判定 planar

mem 二分圖染色 main while %d 復雜度 span inline ont

標簽:二分圖判定。
題解:

  首先可以把題目中給你的那個環給畫出來,這樣就可以發現對於任意一個圖來說,如果兩條邊要相交,就不能讓他們相交,那麽這兩條邊就要一條在裏面一條在外面,如果把環畫成一條鏈,那麽就是一條在下面,一條在上面。於是我們想到對於邊,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; }

[HNOI2010] 平面圖判定 planar