BZOJ 1997: [Hnoi2010]Planar 2-SAT
[Hnoi2010]Planar
Input
Output
Sample Input
2
6 9
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
1 4 2 5 3 6
5 5
1 2
2 3
3 4
4 5
5 1
1 2 3 4 5
Sample Output
NO
YES
Source
题目大意
-
给定一张无向图以及图中的一个哈密顿回路,判断无向图是否为平面图
-
$ n \le 200.m \le 1000 $
题解
-
除去哈密顿回路( $ n $ 个点的环)之外,每条边有环内、环外两个赋值
-
若两条边对应环上的区间有重叠,则不能同时在环内或者环外
-
产生4个条件“若 $ x $ 则 $ y' $ ” “若 $ x' $ 则 $ y $ ” “ 若 $ y $ 则 $ x' $ ” “ 若 $ y' $ 则 $ x $ ”
-
按照 $ 2-SAT $ 模型求解即可
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
#define M 10005
#define N 2005
struct edge{ int v,nxt; }e[N<<8];
int head[N],tot;
void add(int u,int v){
e[++tot].v=v; e[tot].nxt=head[u]; head[u]=tot;
}
int n,m,T,u[M],v[M],c[N],pos[N];
stack<int>s;
int dfn[N],low[N],bel[N],tim,scc,cnt;
bool vis[N];
void tarjan(int u){
dfn[u]=low[u]=++tim; s.push(u); vis[u]=1;
for(int i=head[u];i;i=e[i].nxt)
if(!dfn[e[i].v]){
tarjan(e[i].v);
low[u]=min(low[u],low[e[i].v]);
} else if(vis[e[i].v])
low[u]=min(low[u],dfn[e[i].v]);
if(dfn[u]==low[u]){
++scc;
do{
u=s.top(); s.pop(); vis[u]=0;
bel[u]=scc;
}while(dfn[u]!=low[u]); }
}
inline bool judge(){
for(int i=1;i<=cnt;++i)
if(bel[2*i]==bel[2*i-1]) return 0;
return 1;
}
inline void init(){
memset(head,0,sizeof(head));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
cnt=tot=tim=scc=0;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
for(int i=1;i<=m;++i) scanf("%d %d",&u[i],&v[i]);
for(int i=1;i<=n;++i) scanf("%d",&c[i]);
if(m>3*n-6){ puts("NO"); continue; }
init();
for(int i=1;i<=n;++i) pos[c[i]]=i;
for(int i=1;i<=m;++i){
v[i]=pos[v[i]]; u[i]=pos[u[i]];
if(u[i]>v[i]) swap(u[i],v[i]);
if(v[i]-u[i]==1||(v[i]==n&&u[i]==1)) continue;
u[++cnt]=u[i]; v[cnt]=v[i];
}
for(int i=1;i<=cnt;++i)
for(int j=i+1;j<=cnt;++j)
if((u[i]<u[j]&&u[j]<v[i]&&v[i]<v[j])||(u[j]<u[i]&&u[i]<v[j]&&v[j]<v[i])){
add(2*i-1,2*j);
add(2*i,2*j-1);
add(2*j-1,2*i);
add(2*j,2*i-1);
}
for(int i=1;i<=2*cnt;++i) if(!dfn[i]) tarjan(i);
if(judge()) puts("YES");
else puts("NO");
}
return 0;
}