HDU 3594 Cactus 有向图判强连通及每条边是否仅属于一个环

来源:互联网 发布:大数据合作协议 编辑:程序博客网 时间:2024/05/06 16:21

判断是不是一个环环间以点相连的有向图。

Cactus的意思是仙人掌,不形象啊。

大概思路:

从起点0开始搜,搜到环就把环mark掉(环与搜索路径相连的点不mark,且从此点开始继续搜)。搜完后把所有搜到的点依次作为起点作如此搜索。如果搜到了之前mark的点(搜到起点不算)则说明有边存在于两个环。复杂度O(E)吧=。=

伪代码:

bool 函数(){

1、把起点0放入一个queue(stack也可以,无所谓,仅起储存作用,不过为了和后面的stack区分,就放入queue吧,实际上代码里也是stack:pstk);

2、当queue不为空,拿出front元素,记为start,从此点开始深搜,queue为空跳第7句;

3、搜索时要记录每个点当前搜索的边,下次从这点开始搜时就从这点的下一条边开始,那执行就可能会发现当前点已经没有边可搜了,那就看这个点是否是start点,不是的话返回0(说明不是强连通图,易证),是的话将其退栈,将其mark(事实上如果这点不是0的话,它必定已经被mark了),执行第2句;

4、把搜索的当前点放入stack,instk[u]=1,如果此点被mark了且不是start,返回0(说明有边存在于两个环,可证);  

5、如果搜到一个不在stack内的点,那就放入stack内,同时instk[u]=1,再同时把u放入队列,从这点开始搜,跳回第3句;

6、否则,这个点就是在stack内,把栈顶到此元素之间的所有点退栈(除了刚搜到的这个点),同时将其mark,从这点开始搜,继续从第3句开始执行;

7、扫描所有点,如有点没被mark,那就连弱连通也不是,返回0(代码中没加这句也过了,说明数据给出的都至少是弱连通的,懒得加了),否则返回1。

}

#include<iostream>#include<queue>using namespace std;struct Edge{    int u,v,next;};Edge edge[50000];int N,head[20000],en;void insert(int u,int v){    edge[en].u=u;edge[en].v=v;edge[en].next=head[u];    head[u]=en++;}void get_data(){    memset(head,-1,sizeof(head));    en=0;    int a,b;    scanf("%d",&N);    while(scanf("%d%d",&a,&b),a||b){        insert(a,b);    }}int cur[20000],pstk[20000],psn,stk[20000],sn;bool mark[20000],instk[20000];bool run(){    int i;    for(i=0;i<N;i++)cur[i]=head[i];//初始化当前的边    memset(mark,0,sizeof(mark));    memset(instk,0,sizeof(instk));    sn=psn=0;    pstk[psn++]=0;    int u,v,start;    while(psn){        start=u=pstk[--psn];//第2句        if(cur[u]==-1)continue;        while(true){//----第3句----            if(cur[u]==-1){                if(u==start){                    sn--;                    mark[u]=1;                    break;                }else return 0;            }//--------------            stk[sn++]=u;instk[u]=1;            for(;cur[u]!=-1;){                v=edge[cur[u]].v;cur[u]=edge[cur[u]].next;//把当前边设为下一条,为下次这一点的搜索作准备                if(v!=start&&mark[v])return 0;//第4句                if(!instk[v]){//第5句                    pstk[psn++]=v;                    u=v;break;                }else{//第6句                    while(stk[sn-1]!=v){                        mark[stk[sn-1]]=1;                        sn--;                    }                    u=v;                }            }        }    }//第7句 =。=    return 1;}int main(){    int t;    scanf("%d",&t);    while(t--){        get_data();        if(run())printf("YES\n");        else printf("NO\n");    }    return 0;}


 

原创粉丝点击