1. 程式人生 > 其它 >#2-SAT,平面圖#洛谷 3209 [HNOI2010] 平面圖判定

#2-SAT,平面圖#洛谷 3209 [HNOI2010] 平面圖判定

2-SAT,平面圖

題目傳送門


分析

首先一張圖是平面圖的必要條件為 \(m\leq 3*n-6\)

然後考慮到這題的圖存在哈密爾頓迴路,也就是說非環邊因為跨立形成奇環即為無解

那麼直接拆點跑2-SAT就可以了


程式碼

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=1211; struct node{int y,next;}e[N*N];
int dfn[N],low[N],v[N],stac[N],col[N],rk[N],as[N];
int et,flag,tot,Top,cnt,n,m,X[N*10],Y[N*10];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline signed min(int a,int b){return a<b?a:b;}
inline void tarjan(int x){
	dfn[x]=low[x]=++tot,v[x]=1,stac[++Top]=x;
	for (rr int i=as[x];i;i=e[i].next)
	if (!dfn[e[i].y]){
		tarjan(e[i].y);
		low[x]=min(low[x],low[e[i].y]);
	}else if (v[e[i].y])
	    low[x]=min(low[x],dfn[e[i].y]);
	if (dfn[x]==low[x]){
		rr int y; ++cnt;
		do{
			y=stac[Top--],v[y]=0,
			col[y]=cnt;
		}while (y!=x);
	}
}
inline void add(int x,int y){e[++et]=(node){y,as[x]},as[x]=et;}
signed main(){
	for (rr int T=iut();T;--T){
		n=iut(),m=iut(),flag=et=1,tot=0;
		for (rr int i=1;i<=m;++i) X[i]=iut(),Y[i]=iut();
		for (rr int i=1;i<=n;++i) rk[iut()]=i;
		if (m>3*n-6) {puts("NO"); continue;}
		for (rr int i=1;i<=m;++i){
			X[i]=rk[X[i]],Y[i]=rk[Y[i]];
			if (X[i]>Y[i]) X[i]^=Y[i],Y[i]^=X[i],X[i]^=Y[i];
			if (X[i]+1==Y[i]||(X[i]==1&&Y[i]==n)) v[i]=1;
		}
		for (rr int i=1;i<m;++i) if (!v[i])
		for (rr int j=i+1;j<=m;++j) if (!v[j])
		if ((X[i]<X[j]&&X[j]<Y[i]&&Y[i]<Y[j])||(X[j]<X[i]&&X[i]<Y[j]&&Y[j]<Y[i]))
			add(i,j+m),add(i+m,j),add(j,i+m),add(j+m,i);
		for (rr int i=1;i<=m;++i) v[i]=0;
		for (rr int i=1;i<=m*2;++i) if (!dfn[i]) tarjan(i);
		for (rr int i=1;i<=m;++i)
		    if (col[i]==col[i+m]) {puts("NO"),flag=0; break;}
		if (flag) puts("YES");
		for (rr int i=1;i<=m*2;++i) as[i]=col[i]=dfn[i]=low[i]=0;
	}
	return 0;
}