把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷P3209】[HNOI2010] 平面图判定(平面图性质)

点此看题面

  • 给定一张\(n\)个点\(m\)条边的无向图,保证图中存在一条哈密顿回路,要求判断这是否为一张平面图。
  • 数据组数\(\le100\)\(3\le n\le200,m\le10^4\)

平面图性质

首先给出结论,一张点数\(>2\)的连通平面图满足\(E\le 3V-6\)

根据平面图欧拉公式,有\(V+F-E=2\)

\(V>2\)时,任意一个面至少与三条边相邻,而一条边只会与两个面相邻,也就是说\(3F\le 2E\),代入公式中即可解得\(E\le 3V-6\)

二分图判定

根据平面图的性质,我们可以把边数降到\(O(n)\)级别。

由于保证有一条哈密顿回路,我们抠出这个环来,那么每一条边都可以看成环上两点相连。

每条边要么连在环里侧,要么连在环外侧,而两条有交的边不能同时连在环的同一侧。

把原本的边看成点建图,在有交的边之间连上一条边,问题就变成判断这张新图是否是一张二分图。

代码:\(O(Tn^2)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200
#define M 10000
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
using namespace std;
int n,m,rk[N+5],ex[M+5],ey[M+5],ee,lnk[3*N+5];struct edge {int to,nxt;}e[9*N*N+5];
int c[3*N+5];I bool Col(CI x,CI y) {c[x]=y;for(RI i=lnk[x];i;i=e[i].nxt)//二分图染色
	if(c[e[i].to]==y) return 0;else if(!~c[e[i].to]&&!Col(e[i].to,y^1)) return 0;return 1;}
I bool pd(CI x1,CI y1,CI x2,CI y2) {return x1<x2&&x2<y1&&y1<y2||x2<x1&&x1<y2&&y2<y1;}//判断是否有交
int main()
{
	RI Tt,i,j,x;scanf("%d",&Tt);W(Tt--)
	{
		for(scanf("%d%d",&n,&m),i=1;i<=m;++i) scanf("%d%d",ex+i,ey+i);
		for(i=1;i<=n;++i) scanf("%d",&x),rk[x]=i;if(m>3*n-6) {puts("NO");continue;}//m>3n-6肯定不是平面图
		for(ee=0,i=1;i<=m;++i) lnk[i]=0,c[i]=-1,ex[i]=rk[ex[i]],ey[i]=rk[ey[i]],ex[i]>ey[i]&&(swap(ex[i],ey[i]),0);
		for(i=1;i<=m;++i) for(j=1;j<=m;++j) pd(ex[i],ey[i],ex[j],ey[j])&&add(i,j);//建图
		for(i=1;i<=m;++i) if(!~c[i]&&!Col(i,1)) break;puts(i>m?"YES":"NO");//判断是否为二分图
	}return 0;
}
posted @ 2021-06-22 14:57  TheLostWeak  阅读(136)  评论(0编辑  收藏  举报