P3209 [HNOI2010]平面图判定

题意

题目描述

若能将无向图\(G=(V,E)\)画在平面上使得任意两条无重合顶点的边不相交,则称\(G\)是平面图。判定一个图是否为平面图的问题是图论中的一个重要问题。现在假设你要判定的是一类特殊的图,图中存在一个包含所有顶点的环,即存在哈密顿回路。

输入输出格式

输入格式:

输入文件的第一行是一个正整数\(T\),表示数据组数 (每组数据描述一个需要判定的图)。接下来从输入文件第二行开始有\(T\)组数据,每组数据的第一行是用空格隔开的两个正整数\(N\)和\(M\),分别表示对应图的顶点数和边数。紧接着的\(M\)行,每行是用空格隔开的两个正整数\(u\)和\(v\left(1\leq u,v\leq N\right)\),表示对应图的一条边\(\left(u,v\right)\), 输入的数据保证所有边仅出现一次。每组数据的最后一行是用空格隔开的\(N\)个正整数,从左到右表示对应图中的一个哈密顿回路\(V_1,V_2,\dots ,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\leq1000\)。

输出格式:

包含\(T\)行,若输入文件的第\(i\)组数据所对应图是平面图,则在第\(i\)行输出 \(\text{YES}\),否则在第\(i\)行输出\(\text{NO}\),注意均为大写字母。

输入输出样例

输入样例#1:

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

输出样例#1:

NO
YES

思路

这题毒瘤,要先转对偶图... --huyufeifei

其实这题也没那么毒瘤,直接\(2-SAT\)或者并查集就好了。

我们先把哈密顿回路搬出来,画成一个圆,再来考虑图上其他的边。其他的边有两种画法:画在圆内,画在圆外。有些边,如果都画在圆内,就会相交,不符合平面图的性质;而如果他们都画在圆外,也会相交。所以我们可以把边拿出来,把其是否画在圆内作为这条边的边权,两条边不可相交作为其限制条件,做\(2-SAT\)就好了。当然,\(alec\)神仙写的是并查集做法,也是十分可行的。

还有一个剪枝:显然平面图中的边的数量不能太多,因为图越稠密越难画出平面图,所以当当前状况下边数过多时,我们就可以直接判NO。上网查资料得\(m\leq 3n-2\)(这个是可以用欧拉公式证明的。 --logeadd),加上剪枝就能跑得很快了。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN=205;
const int MAXM=605;
int T,n,m,id[MAXN],inv[MAXN],u[10005],v[10005];
int nn,U[MAXM],V[MAXM];
int cnt,top[MAXM<<1],to[(MAXM*MAXM)<<2],nex[(MAXM*MAXM)<<2];
int tot,js,dfn[MAXM<<1],low[MAXM<<1],bel[MAXM<<1];
bool cir[MAXN][MAXN],vis[MAXM<<1];
stack<int>S;
int read()
{
int re=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
return re;
}
void add_edge(int x,int y){to[++cnt]=y,nex[cnt]=top[x],top[x]=cnt;}
void tarjan(int now)
{
dfn[now]=low[now]=++tot,vis[now]=true,S.push(now);
for(int i=top[now];i;i=nex[i])
if(!dfn[to[i]]) tarjan(to[i]),low[now]=min(low[now],low[to[i]]);
else if(vis[to[i]]) low[now]=min(low[now],low[to[i]]);
if(dfn[now]==low[now])
{
bel[now]=++js,vis[now]=false;
while(S.top()!=now) bel[S.top()]=js,vis[S.top()]=false,S.pop();
S.pop();
}
}
int main()
{
T=read();
while(T--)
{
n=read(),m=read(),nn=cnt=tot=js=0;
memset(id,0,sizeof id);
memset(inv,0,sizeof inv);
memset(u,0,sizeof u);
memset(v,0,sizeof v);
memset(U,0,sizeof U);
memset(V,0,sizeof V);
memset(top,0,sizeof top);
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
memset(bel,0,sizeof bel);
memset(cir,false,sizeof cir);
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
if(x>y) swap(x,y);
u[i]=x,v[i]=y;
}
for(int i=1;i<=n;i++)
{
int x=read();
id[x]=i,inv[i]=x;
if(i!=1)
{
int y=inv[i-1];
if(x>y) swap(x,y);
cir[x][y]=true;
}
}
if(m>3*n-6)
{
puts("NO");
continue;
}
if(inv[1]<inv[n]) cir[inv[1]][inv[n]]=true;
else cir[inv[n]][inv[1]]=true;
for(int i=1;i<=m;i++) if(!cir[u[i]][v[i]]) U[++nn]=u[i],V[nn]=v[i];
for(int i=1;i<=nn;i++)
for(int j=i+1;j<=nn;j++)
{
int x=id[U[i]],y=id[V[i]],xx=id[U[j]],yy=id[V[j]];
if(x>y) swap(x,y);
if(xx>yy) swap(xx,yy);
if((x<xx&&xx<y&&y<yy)||(xx<x&&x<yy&&yy<y)) add_edge(i,j+nn),add_edge(i+nn,j),add_edge(j,i+nn),add_edge(j+nn,i);
}
for(int i=1;i<=(nn<<1);i++) if(!dfn[i]) tarjan(i);
bool ans=true;
for(int i=1;i<=nn;i++)
if(bel[i]==bel[i+nn])
{
ans=false;
break;
}
if(ans) puts("YES");
else puts("NO");
}
return 0;
}

Luogu P3209 [HNOI2010]平面图判定(2-SAT)的更多相关文章

  1. P3209 [HNOI2010]平面图判定

    P3209 [HNOI2010]平面图判定 哈密尔顿环之外的任意一条边,要么连在环内部,要么连在环外部 判断两条边在同一部分会相交,则这两条边必须分开 那么把边看作点连边,跑二分图染色就行 #incl ...

  2. 洛谷 P3209 [HNOI2010] 平面图判定

    链接: P3209 题意: 给出 \(T\) 张无向图 \((T\leq100)\),并给出它对应的哈密顿回路,判断每张图是否是平面图. 分析: 平面图判定问题貌似是有线性做法的,这里给出链接,不是本 ...

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

    传送门 看到哈密顿回路就被吓傻了……结果没有好好考虑性质…… 首先,平面图有个性质:边数小于等于$3n-6$(我也不知道为啥),边数大于这个的直接pass 然后考虑原图,先把哈密顿回路单独摘出来,就是 ...

  4. bzoj1997 [HNOI2010]平面图判定Plana

    bzoj1997 [HNOI2010]平面图判定Planar 链接 bzoj luogu 思路 好像有很多种方法过去.我只说2-sat 环上的边,要不在里面,要不在外边. 有的边是不能同时在里面的,可 ...

  5. [BZOJ1997][HNOI2010] 平面图判定

    Description Input Output     是的..BZOJ样例都没给.     题解(from 出题人): 如果只考虑简单的平面图判定,这个问题是非常不好做的. 但是题目中有一个条件— ...

  6. [HNOI2010]平面图判定

    Description: 若能将无向图 \(G=(V, E)\) 画在平面上使得任意两条无重合顶点的边不相交,则称 \(G\) 是平面图.判定一个图是否为平面图的问题是图论中的一个重要问题.现在假设你 ...

  7. Luogu3209 HNOI2010 平面图判定 平面图、并查集

    传送门 题意:$T$组数据,每组数据给出一个$N$个点,$M$条边,并存在一个$N$元环的图,试判断其是否为一个可平面图(如果存在一种画法,使得该图与给出的图同构且边除了在顶点处以外互相不相交,则称其 ...

  8. [HNOI2010] 平面图判定 planar

    标签:二分图判定.题解: 首先可以把题目中给你的那个环给画出来,这样就可以发现对于任意一个图来说,如果两条边要相交,就不能让他们相交,那么这两条边就要一条在里面一条在外面,如果把环画成一条链,那么就是 ...

  9. BZOJ1997 HNOI2010 平面图判定 planar (并查集判二分图)

    题意 判断一个存在哈密顿回路的图是否是平面图. n≤200,m≤10000n\le200,m\le10000n≤200,m≤10000 题解 如果一定存在一个环,那么连的边要么在环里面要么在外面.那么 ...

随机推荐

  1. Android欢迎页短暂白屏

    在style中application theme下添加以下代码: <item name="android:windowIsTranslucent" >true</ ...

  2. duilib教程之duilib入门简明教程10.界面设计器 DuiDesigner

    上一个教程讲解了怎么布局最大化.最小化.关闭按钮,但是如果手动去计算这三个按钮的位置和大小的话,非常的不直观,也很不方便.    所以这一章准备介绍duilib的UI设计器,由于这个设计器很不完善,也 ...

  3. LUOGU P2564 [SCOI2009]生日礼物 (队列+模拟)

    传送门 解题思路 还是比较好想的,用一个队列,然后把所有点放在一起排个序,依次入队.每次检查队头元素的种类是否为当前入队元素种类,是的话就一直\(pop\),每次更新答案即可. 代码 #include ...

  4. error LNK2001: unresolved external symbol _main解决办法(zz)

    error LNK2001: unresolved external symbol _main解决办法   解决外部符号错误:_main,_WinMain@16,__beginthreadex -!t ...

  5. VS2010-MFC(对话框:颜色对话框)

    转自:http://www.jizhuomi.com/software/177.html 颜色对话框大家肯定也不陌生,我们可以打开它选择需要的颜色,简单说,它的作用就是用来选择颜色.MFC中提供了CC ...

  6. VS2010-MFC(对话框:属性页对话框及相关类的介绍)

    转自:http://www.jizhuomi.com/software/164.html 一 属性页对话框的分类 属性页对话框想必大家并不陌生,XP系统中桌面右键点属性,弹出的就是属性页对话框,它通过 ...

  7. PHP面向对象魔术方法之__toString函数

    l 基本介绍: 当我们希望将一个对象当做字符串来输出时,就会触发__toString魔术方法. <?php header('content-type:text/html;charset=utf- ...

  8. Java 内部类,成员类,局部类,匿名类等

    根据内部类的位置不同,可将内部类分为 :成员内部类与局部内部类. class outer{ class inner{//成员内部类 } public void method() { class loc ...

  9. 常用终止python程序方法

    方法1:采用sys.exit(0)正常终止程序,从图中可以看到,程序终止后shell运行不受影响. 方法2:采用os._exit(0)关闭整个shell,从图中看到,调用sys._exit(0)后整个 ...

  10. 一个上午,勉强记住了几种不同语言编译PE的启动函数

    VC:启动函数最乱,三大函数都在后面.前面8个PUSH DELPHI7:启动函数最整洁,2.3.4.2,形式排队 VB:启动函数最好记,12个0.... 汇编:三大函数距离最紧凑,除VB外,启动函数最 ...