• 有向图寻找(一个)奇环 -- find an oddcycle in directed graph


    /// the original blog is http://www.cnblogs.com/tmzbot/p/5579020.html , automatic crawling without link to original blog is unallowed.

    判定 + 寻找一组解

    (感觉这个东西挺有意思的记录一下..)

    /// the original blog is http://www.cnblogs.com/tmzbot/p/5579020.html , automatic crawling without link to original blog is unallowed.

    Algorithm.A

    暴力吧.. 暴力枚举每个环判断一下.. (不知道什么复杂度..反正大概是指数级别的,说错了别打我,怕疼)

    /// the original blog is http://www.cnblogs.com/tmzbot/p/5579020.html , automatic crawling without link to original blog is unallowed.

    Algorithm.B

    先把强联通分量搞出来. (O(n+m))

    然后考虑对点dfs二染色并同时维护传递闭包(这里传递闭包的定义是(vin mathtt{closure}(u))当且仅当dfn[v]<dfn[u]且u可以访问到v),枚举出边(u,v)的时候若有一边是两端同色(这条边一定是返祖边或横向边,理由dfn[u]>dfn[v]),如果是返祖边(inStack[v])那就不用做了,如果是横向边考虑v的传递闭包中的u祖先, 判断是不是奇环. 总复杂度(O(n^2)). 用线段树启发式合并的技巧我们就能得到一个优秀又难写的(O(n^2log{n}))算法.

    /// the original blog is http://www.cnblogs.com/tmzbot/p/5579020.html , automatic crawling without link to original blog is unallowed.

    Algorithm.C

    我们考虑一个出发点不太一样的做法.

    我们拆点, 将一个点u分为两个点W(u)和B(u).原图需要加入边(u,v)的时候我们加入W(u)->B(v), B(u)->W(v).

    那么考虑原图中存在一个奇环当且仅当存在u使得W(u)可以达到B(u)或B(u)可以达到W(u),把这段路径搞下来变成原来节点就是要找的环了.

    那么我们对于每个点W(u)和B(u)都dfs一下看看能不能到达就好了. 因为对称性所以B(u)上是无需dfs的. (O(n^2))

    /// the original blog is http://www.cnblogs.com/tmzbot/p/5579020.html , automatic crawling without link to original blog is unallowed.

    Algorithm.D

    然而好像无需这么干..

    若一个有奇环a,b,c,...,x,y(不要管它字母是怎么写的,其中元素有多少个,反正是奇数个), 不失一般性我们认为a是最先访问到的节点,而此时b,c,...,x,y都没有被访问过, 显然需要存在W(a)->B(b)->W(c)->...->W(y)->B(a)

    在这条路径上除了a以外颜色都是固定的.我们假设没有按照这条路径先走而是走了例如W(a)->B(X)->W(y)的路径, 显然奇偶性是没有改变的, 那么要是原来能找到奇环那么先在也能走到奇环, 而只要W(a)能访问到W(y)那么一定从W(a)出发会走到W(y), 那肯定能发现一个奇环.

    如果存在一个奇环显然有一个节点是最先访问的,而此时所有其它奇环上的顶点都没被访问过.

    那么只要有一个奇数环一定能找到.

    复杂度是(O(n+m))的.

    一道裸题的代码

    /// the original blog is http://www.cnblogs.com/tmzbot/p/5579020.html , automatic crawling without link to original blog is unallowed.
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    const int maxn = 200010;
    const int maxm = 2000010;
    namespace Graph{
    	struct ed{
    		int t;
    		ed* n;
    	}*h[maxn],Al[maxm],*p=Al;
    	inline void ade(int f,int t){ *p=(ed){t,h[f]}; h[f]=p++; }
    	bool vis[maxn], inq[maxn];
    	int stk[maxn],stt;
    	int cycle[maxn], cycleLen;
    	void dfs(int n){
    		vis[n]=inq[n]=1;
    		stk[stt++]=n;
    		for(ed*i=h[n];i;i=i->n){
    			int vx;
    			if(inq[vx=(i->t^1)]){
    				while(stk[--stt]!=vx)
    					cycle[cycleLen++]=stk[stt];
    				cycle[cycleLen++]=vx;
    			}else if(!vis[i->t]) dfs(i->t);
    			if(cycleLen) return;
    		} --stt;
    		inq[n]=0;
    	}
    	inline void init(int n){
    		for(int i=2,_=n*2+1;i<=_;++i){
    			inq[i]=vis[i]=0;
    			h[i]=NULL;
    		} p=Al, cycleLen=0, stt=0;
    	}
    	inline void work(){
    		int n,m; scanf("%d%d",&n,&m);
    		init(n);
    		for(int i=1,a,b;i<=m;++i){
    			scanf("%d%d",&a,&b);
    			ade(a<<1,b<<1|1);
    			ade(a<<1|1,b<<1);
    		}
    		for(int i=2,_=2*n+1;i<=_;++i) if(!vis[i]){
    			dfs(i);
    			if(cycleLen) break;
    		}
    		if(cycleLen){
    			printf("1
    %d
    ",cycleLen);
    			for(int i=cycleLen-1;~i;--i) printf("%d
    ",cycle[i]>>1);
    		}else
    			printf("-1
    ");
    	}
    } using namespace Graph;
    int main(){
    	int t; scanf("%d",&t);
    	while(t--) work();
    	return 0;
    }
    
  • 相关阅读:
    工厂模式一
    面向对象的简单理解二
    工厂模式三
    线程的简单学习
    nyoj35 表达式求值
    nyoj305 表达式求值
    poj1298 The Hardest Problem Ever
    poj1363 Rails
    hdu2036 改革春风吹满地
    nyoj467 中缀式变后缀式
  • 原文地址:https://www.cnblogs.com/tmzbot/p/5579020.html
Copyright © 2020-2023  润新知