博客迁移计划10
BZOJ已经凉了...
[Hnoi2010]Planar
Description
若能将无向图\(G=(V,E)\)画在平面上使得任意两条无重合顶点的边不相交,则称\(G\)是平面图。判定一个图是否为平面图的问题是图论中的一个重要问题。现在假设你要判定的是一类特殊的图,图中存在一个包含所有顶点的环,即存在哈密顿回路。
Input
输入文件的第一行是一个正整数\(T\),表示数据组数 (每组数据描述一个需要判定的图)。接下来从输入文件第二行开始有\(T\)组数据,每组数据的第一行是用空格隔开的两个正整数\(N\)和\(M\),分别表示对应图的顶点数和边数。紧接着的\(M\)行,每行是用空格隔开的两个正整数\(u\)和\(v \left(1\leq u,v\leq N\right)\),表示对应图的一条边\(\left(u,v\right)\),输入的数据保证所有边仅出现一次。每组数据的最后一行是用空格隔开的\(N\)个正整数,从左到右表示对应图中的一个哈密顿回路:\(V_1,V_2,…,V_N\),即对任意\(i\not=j\)有\(V_i\not=V_j\)且对任意\(1\leq i\leq N-1\)有\(\left(V_i,V_i-1\right)\in E\)及\(\left(V_1,V_N\right)\in E\)。输入的数据保证\(100\%\)的数据满足\(T\leq100,3\leq N\leq200,M\leq10000\)。
Output
包含\(T\)行,若输入文件的第\(i\)组数据所对应图是平面图,则在第\(i\)行输出\(\text{YES}\),否则在第\(i\)行输出\(\text{NO}\),注意均为大写字母
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;
}