• [BZOJ1997][HNOI2010]Planar


    bzoj
    luogu

    题意

    给你一张含有一条哈密顿回路的无向图(哈密顿回路就是经过每个店恰好一次),判断这张图是不是平面图(平面图就是可以画在平面上使边不相交)。

    sol

    首先有一个平面图定理:一张平面图的边数不超过(3N-6)(其中(N)是点数)
    这样就把边数降到了(O(n))级别。
    把环抠出来,剩下的边就只能从环的里面连或者从环的外面连。
    问题转化成(2-sat)
    直接(O(n^2))建边即可。

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 605;
    const int M = 4e5+5;
    struct edge{int u,v;}E[M];
    int T,n,m,p[N],tot,to[M],nxt[M],head[N],cnt,dfn[N],low[N],tim,Stack[N],top,vis[N],bel[N],scc;
    bool Cross(int l1,int r1,int l2,int r2)
    {
    	if (l1>l2) swap(l1,l2),swap(r1,r2);
    	return l1<l2&&l2<r1&&r1<r2;
    }
    void link(int u,int v)
    {
    	to[++cnt]=v;nxt[cnt]=head[u];
    	head[u]=cnt;
    }
    void Tarjan(int u)
    {
    	dfn[u]=low[u]=++tim;
    	Stack[++top]=u;vis[u]=1;
    	for (int e=head[u];e;e=nxt[e])
    		if (!dfn[to[e]]) Tarjan(to[e]),low[u]=min(low[u],low[to[e]]);
    		else if (vis[u]) low[u]=min(low[u],dfn[to[e]]);
    	if (dfn[u]==low[u])
    	{
    		++scc;int v;
    		do{
    			v=Stack[top--];
    			vis[v]=0;bel[v]=scc;
    		}while (u!=v);
    	}
    }
    bool check()
    {
    	for (int i=1;i<=tot;++i)
    		if (bel[i]==bel[i+tot]) return false;
    	return true;
    }
    int main()
    {
    	T=gi();
    	while (T--)
    	{
    		memset(head,0,sizeof(head));
    		memset(dfn,0,sizeof(dfn));
    		cnt=tot=scc=tim=0;
    		n=gi();m=gi();
    		for (int i=1;i<=m;++i) E[i]=(edge){gi(),gi()};
    		for (int i=1;i<=n;++i) p[gi()]=i;
    		if (m>3*n-6) {puts("NO");continue;}
    		for (int i=1;i<=m;++i)
    		{
    			E[i].u=p[E[i].u];E[i].v=p[E[i].v];
    			if (E[i].u>E[i].v) swap(E[i].u,E[i].v);
    			if (E[i].u+1!=E[i].v&&!(E[i].u==1&&E[i].v==n)) E[++tot]=E[i];
    		}
    		for (int i=1;i<=tot;++i)
    			for (int j=i+1;j<=tot;++j)
    				if (Cross(E[i].u,E[i].v,E[j].u,E[j].v))
    					link(i,j+tot),link(j,i+tot),link(i+tot,j),link(j+tot,i);
    		for (int i=1;i<=(tot<<1);++i) if (!dfn[i]) Tarjan(i);
    		puts(check()?"YES":"NO");
    	}
    	return 0;
    }
    
  • 相关阅读:
    linux最简单项目部署
    sql索引
    /etc/profile和~/.bash_profile区别
    Linux下查找软件的目录位置
    为什么要使用消息队列?
    idea中常用的快捷键
    PAT 甲级 1023 Have Fun with Numbers (20分)
    PAT《算法笔记》
    Text 2
    Text-1
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8682029.html
Copyright © 2020-2023  润新知