2018.11.06【HNOI2010】【洛谷P3209】【BZOJ1997】平面圖判定Planar(二分圖染色)(結論題)
阿新 • • 發佈:2018-11-10
BZOJ傳送門
洛谷傳送門
解析:
首先記住一個結論:對於任意平面圖都有
證明一下:只考慮極大平面圖(即點數一定時,邊數達到最大的平面圖)。其他的情況邊數都小於同頂點數的極大平面圖。
首先,極大平面圖的每個平面由3條邊圍成,不然總是能夠在這個形狀中繼續連一條對角線加邊。
令
為該平面圖面數,
為邊數,
為點數。
由於是極大平面圖,所以有
,即每條邊被兩個平面共享,每個平面由三條邊圍成。
由平面圖的尤拉公式 (直接將拓撲學的立體圖形對映到平面上即可得到),那麼極大平面圖有 。其他情況
所以對於任意平面圖,總是有 。
那麼我們就排除那些不符合題意的圖,將邊的規模優化到 了。
由於這道題的圖都有哈密爾頓迴路,所以可以亂搞一下。
將哈密爾頓迴路看作一個圈,剩下的邊要麼是圓上的弦,要麼就在圓外。
顯然如果兩條邊有交點,它們必須處於不同的兩側,
所以我們可以將它們連邊,隨後染色判斷一下是否是二分圖就行了。
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=205,M=10004;
vector<int> edge[N*3+8];
int a[M],b[M];
int H[N];
inline void addedge(int u,int v){
edge[u].push_back(v);
edge[v].push_back(u);
}
int col[N*3+8];
int T,n,m;
inline void clear(){
memset(col,-1,sizeof col);
for(int re i=1;i<=m;++i)edge[i].clear();
}
inline bool dye(int u){
for(int re e=0;e<edge[u].size();++e){
int re v=edge[u][e];
if(col[v]==col[u])return false;
if(col[v]==-1){
col[v]=col[u]^1;
if(!dye(v))return false;
}
}
return true;
}
signed main(){
T=getint();
while(T--){
n=getint();
m=getint();
for(int re i=1;i<=m;++i){
a[i]=getint();
b[i]=getint();
}
for(int re i=1;i<=n;++i)H[getint()]=i;
if(m>3*n-6){
puts("NO");
continue;
}
clear();
for(int re i=1;i<=m;++i)
for(int re j=i+1;j<=m;++j){
int u1=H[a[i]],v1=H[b[i]],u2=H[a[j]],v2=H[b[j]];
if(u1>v1)swap(u1,v1);
if(u2>v2)swap(u2,v2);
if((u1<u2&&u2<v1&&v1<v2)||(u2<u1&&u1<v2&&v2<v1)){
addedge(i,j);
}
}
bool flag=true;
for(int re i=1;i<=m;++i){
if(~col[i])continue;
col[i]=0;
if(!dye(i)){
flag=false;
break;
}
}
puts(flag?"YES":"NO");
}
return 0;
}