1. 程式人生 > >2018.11.06【HNOI2010】【洛谷P3209】【BZOJ1997】平面圖判定Planar(二分圖染色)(結論題)

2018.11.06【HNOI2010】【洛谷P3209】【BZOJ1997】平面圖判定Planar(二分圖染色)(結論題)

BZOJ傳送門

洛谷傳送門


解析:

首先記住一個結論:對於任意平面圖都有 E 3 V

6 |E|\leq3|V|-6

證明一下:只考慮極大平面圖(即點數一定時,邊數達到最大的平面圖)。其他的情況邊數都小於同頂點數的極大平面圖。

首先,極大平面圖的每個平面由3條邊圍成,不然總是能夠在這個形狀中繼續連一條對角線加邊。

r

r 為該平面圖面數, m m 為邊數, n n 為點數。
由於是極大平面圖,所以有 3
r = 2 m 3r=2m
,即每條邊被兩個平面共享,每個平面由三條邊圍成。

由平面圖的尤拉公式 n m + r = 2 n-m+r=2 (直接將拓撲學的立體圖形對映到平面上即可得到),那麼極大平面圖有 m = 3 n 6 m=3n-6 。其他情況 m < m = 3 n 6 m'<m=3n-6

所以對於任意平面圖,總是有 m 3 n 6 m\le 3n-6

那麼我們就排除那些不符合題意的圖,將邊的規模優化到 O ( n ) O(n) 了。

由於這道題的圖都有哈密爾頓迴路,所以可以亂搞一下。

將哈密爾頓迴路看作一個圈,剩下的邊要麼是圓上的弦,要麼就在圓外。

顯然如果兩條邊有交點,它們必須處於不同的兩側,

所以我們可以將它們連邊,隨後染色判斷一下是否是二分圖就行了。


程式碼:

#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;
}