zoukankan      html  css  js  c++  java
  • [HNOI2010]平面图判定

    洛咕

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

    分析:寻思了半天,题目中的平面图应该就是我们画的那种平面图,然后每条边不能相交这种吧.

    首先根据平面图性质特判(不要问我怎么知道的):(m>3*n-6),就一定不会是平面图,那么边数直接从(10000)级别下降到了(600)级别(就可以暴力做了???).

    然后题目中给了我们一个环,不妨设这个环的节点编号就是(1->2->3->...->n),那么对于剩下的非环上的边,它们的边要么在环外要么在环内,就可以把每条边拆成两个,一个表示在环内,一个表示在环外,然后根据(2-SAT)连边跑(tarjan)判定即可.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=605;
    const int M=100005;//这个数组我也不知道要开多大
    struct edge{int x,y;}E[M],e[M];
    int tot,head[N],nxt[M],to[M],a[N];
    inline void add(int a,int b){nxt[++tot]=head[a];head[a]=tot;to[tot]=b;}
    int top,tim,num,dfn[N],low[N],st[N],color[N];
    inline void tarjan(int u){
        dfn[u]=low[u]=++tim;st[++top]=u;
        for(int i=head[u];i;i=nxt[i]){
            int v=to[i];
            if(!dfn[v]){
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(!color[v]){
                low[u]=min(low[u],dfn[v]);
            }
        }
        if(low[u]==dfn[u]){
            color[u]=++num;
            while(st[top]!=u){
                color[st[top]]=num;
                --top;
            }
            --top;
        }
    }
    int main(){
    	int T=read();
    	while(T--){
    		int n=read(),m=read();
    		tot=0;tim=0;top=0;num=0;
    		memset(dfn,0,sizeof(dfn));
    		memset(head,0,sizeof(head));
    		memset(color,0,sizeof(color));//多组数据初始化
    		for(int i=1;i<=m;++i)E[i].x=read(),E[i].y=read();
    		for(int i=1;i<=n;++i)a[read()]=i;//把节点重新编号
    		if(m>3*n-6){puts("NO");continue;}//特判
    		int cnt=0;
    		for(int i=1;i<=m;++i){
    			E[i].x=a[E[i].x],E[i].y=a[E[i].y];//赋予新的编号
    			if(E[i].x>E[i].y)swap(E[i].x,E[i].y);
    			if(E[i].x+1!=E[i].y&&!(E[i].x==1&&E[i].y==n))e[++cnt].x=E[i].x,e[cnt].y=E[i].y;//非环上的边就保留下来
    		}
    		for(int i=1;i<=cnt;++i)
    			for(int j=1;j<=cnt;++j)
    				if(e[i].x<e[j].x&&e[j].x<e[i].y&&e[i].y<e[j].y)
    //只有节点编号相交叉的两条边才可能相交,这种边就需要讨论在环外还是环内
    					add(i,j+cnt),add(j,i+cnt),add(i+cnt,j),add(j+cnt,i);
    		for(int i=1;i<=cnt*2;++i)if(!dfn[i])tarjan(i);
    		int bj=1;
    		for(int i=1;i<=cnt;++i)if(color[i]==color[i+cnt]){bj=0;break;}
    		if(bj)puts("YES");else puts("NO");
    	}
        return 0;
    }
    
    
  • 相关阅读:
    第60届IMO 第5题
    第31届IMO 第2题
    洛谷【P1595 信封问题】 题解
    洛谷【P2022 有趣的数】 题解
    洛谷【P5004 专心OI
    04-----jQuery的属性操作
    03-----jQuery动画效果
    02-----jQuery的选择器
    01-----jQuery介绍
    17-----案例
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11660646.html
Copyright © 2011-2022 走看看