1. 程式人生 > >洛谷P3209 [HNOI2010]平面圖判定(2-SAT)

洛谷P3209 [HNOI2010]平面圖判定(2-SAT)

mes flag fin dig 判斷 lag test wap pen

傳送門

看到哈密頓回路就被嚇傻了……結果沒有好好考慮性質……

首先,平面圖有個性質:邊數小於等於$3n-6$(我也不知道為啥),邊數大於這個的直接pass

然後考慮原圖,先把哈密頓回路單獨摘出來,就是一個環。對於每一條不在哈密頓回路上的邊,有兩種可能,一種是在環內,一種是在環外

我們用點來表示每一條邊,把每一個點拆成兩個分別表示這條邊是在環內還是環外。對於兩條邊$i,j$,如果他們同時在環外或環內會交叉,那麽就相當於有了約束條件,轉化成一個2-SAT問題即可

至於連邊,我們設$i$表示在環內,$i+m$表示在環外,如果$i,j$同在環內或環外會相交,那麽連邊$(i,j+m),(i+m,j),(j,i+m),(j+m,i)$,即他們永遠不能同時在環內或環外

至於如果判斷是否會相交,我們可以把環拆開,然後判斷同在一側是否會相交即可

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #define mem(a) (memset(a,0,sizeof(a)))
 6 #define swap(x,y) (x^=y^=x^=y)
 7 using namespace std;
 8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 9
char buf[1<<21],*p1=buf,*p2=buf; 10 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} 11 inline int read(){ 12 #define num ch-‘0‘ 13 char ch;bool flag=0;int res; 14 while(!isdigit(ch=getc())) 15 (ch==-)&&(flag=true); 16 for
(res=num;isdigit(ch=getc());res=res*10+num); 17 (flag)&&(res=-res); 18 #undef num 19 return res; 20 } 21 const int N=2e4+5,M=1e5+5; 22 int head[N],Next[M],ver[M],tot; 23 inline void add(int u,int v){ 24 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 25 } 26 int dfn[N],low[N],bl[N],st[N],num,cnt,top,n,m,k; 27 void tarjan(int u){ 28 dfn[u]=low[u]=++num,st[++top]=u; 29 for(int i=head[u];i;i=Next[i]){ 30 int v=ver[i]; 31 if(!dfn[v]) tarjan(v),cmin(low[u],low[v]); 32 else if(!bl[v]) cmin(low[u],dfn[v]); 33 } 34 if(low[u]==dfn[u]) for(++cnt;st[top+1]!=u;--top) bl[st[top]]=cnt; 35 } 36 inline bool check(){ 37 for(int i=1,l=m<<1;i<=l;++i) if(!dfn[i]) tarjan(i); 38 for(int i=1;i<=m;++i) 39 if(bl[i]==bl[i+m]) return false; 40 return true; 41 } 42 int rev[205],cir[205][205],E[205],eu[N],ev[N]; 43 void clear(){ 44 mem(head),mem(dfn),mem(low),mem(bl),mem(st),mem(cir); 45 num=cnt=top=tot=0; 46 } 47 void solve(){ 48 clear(); 49 n=read(),m=read(),k=0; 50 for(int i=1;i<=m;++i){ 51 eu[i]=read(),ev[i]=read(); 52 if(eu[i]>ev[i]) swap(eu[i],ev[i]); 53 } 54 for(int i=1;i<=n;++i){ 55 rev[E[i]=read()]=i; 56 if(i>1){ 57 int u=E[i-1],v=E[i]; 58 u<v?cir[u][v]=1:cir[v][u]=1; 59 } 60 } 61 if(m>3*n-6) return (void)(puts("NO")); 62 for(int i=1;i<=m;++i) 63 if(!cir[eu[i]][ev[i]]) eu[++k]=eu[i],ev[k]=ev[i]; 64 m=k; 65 for(int i=1;i<m;++i) 66 for(int j=i+1;j<=m;++j){ 67 int u=rev[eu[i]],v=rev[ev[i]],x=rev[eu[j]],y=rev[ev[j]]; 68 if(u>v) swap(u,v);if(x>y) swap(x,y); 69 if((u<x&&v>x&&v<y)||(u>x&&u<y&&v>y)){ 70 add(i,j+m),add(j,i+m),add(i+m,j),add(j+m,i); 71 } 72 } 73 puts(check()?"YES":"NO"); 74 } 75 int main(){ 76 // freopen("testdata.in","r",stdin); 77 int T=read(); 78 while(T--) solve(); 79 return 0; 80 }

洛谷P3209 [HNOI2010]平面圖判定(2-SAT)