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

传送门

看到哈密顿回路就被吓傻了……结果没有好好考虑性质……

首先,平面图有个性质:边数小于等于$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 }
原文地址:https://www.cnblogs.com/bztMinamoto/p/9786066.html