zoukankan      html  css  js  c++  java
  • 云里雾里学Tarjan(强连通分量)

    首先让我先来说一说关于强连通分量的一些疑惑

    1、当我已经知道了我要走的下一步节点在栈中,我能不能把比较中的DFN写成LOW?

    2、如果low[v]>=dfn[u],此时u就是割点,这个东西怎么证明?

    这里链接两篇Tarjan算法写的非常好的博客:

    1、全网最!详!细!tarjan算法讲解

    2、割点(Tarjan算法)

    ↑洛谷有模板

    下面是鄙人写的裸的Tarjan求图中强连通分量的代码!

    //Tarjan基本的算法实现 
    
    #include<bits/stdc++.h>
    using namespace std;
    struct sd{
    	int v,next;
    }edge[1001];
    int DFN[1001],LOW[1001];
    int stk[1001],head[1001],vis[1001],cnt,tot,index,n,m;
    void add(int x,int y)
    {//链式前向星 
    	edge[++cnt].next=head[x];
    	edge[cnt].v=y;
    	head[x]=cnt;return; 
    }
    void tarjan(int x)
    {
    	DFN[x]=LOW[x]=++tot;
    	stk[++index]=x;
    	vis[x]=1;
    	for(int i=head[x];i;i=edge[i].next)
    	{
    		if(!DFN[edge[i].v])
    		tarjan(edge[i].v),LOW[x]=min(LOW[x],LOW[edge[i].v]);
    		else if(vis[edge[i].v])
    		LOW[x]=min(LOW[x],DFN[edge[i].v]);
    	}
    	if(DFN[x]==LOW[x])
    	{
    		while(stk[index]!=x)
    			printf("%d ",stk[index]),vis[stk[index]]=0,index--;
    		printf("%d
    ",stk[index]),vis[stk[index]]=0,index--;
    	}
    } 
    int main()
    {
    	scanf("%d%d",&n,&m);
    	int x,y;
    	for(int i=1;i<=m;++i)
    	{
    		scanf("%d%d",&x,&y);
    		add(x,y);
    	}
    	for(int i=1;i<=n;++i)
    	{
    		if(!DFN[i]) tarjan(i);
    	}
    	return 0;
    } 
    /*
    6 8
    1 2
    1 4
    2 3
    3 6
    2 5
    5 6
    4 5
    5 1
    */
    

    下面是我给出的求割点的tarjan算法程序。我还是有一些东西没有搞懂。(带有注释)

    这里给一张图方便理解:(红色的是DFN,蓝色的是LOW)

    例题:P3388 【模板】割点(割顶)

    //tarjan算法求割点,我好像自己也不是很懂
    #include<bits/stdc++.h>
    using namespace std;
    const int N=100010;
    struct sd{
    	int next,v;
    }edge[2*N];
    int head[N],DFN[N],LOW[N],cnt=0,tot=0,n,m; 
    bool judge[N];
    void add(int x,int y)
    {
    	edge[++cnt].next=head[x];
    	edge[cnt].v=y;
    	head[x]=cnt;
    }
    void tarjan(int x,int fa)
    {
    	int child=0;
    	DFN[x]=LOW[x]=++tot;
    	for(int i=head[x];i;i=edge[i].next)
    	{
    		int v=edge[i].v;//v是要到达的点 
    		if(!DFN[v])
    		{
    			tarjan(v,fa);
    			LOW[x]=min(LOW[x],LOW[v]);
    			if(LOW[v]>=DFN[x]&&x!=fa)judge[x]=true;//就是说明下一个点的最早能追溯到的节点比当前点的dfs序大或等于 
    			if(x==fa)child++;//找回来了,说明已经遍历完了一颗子树
    		}
    		LOW[x]=min(LOW[x],DFN[v]);//?? 判断回边因为是无向图!!!这里不能改的过于大了不能改成LOW否则容易出问题! 
    	}
    	if(child>=2&&x==fa)judge[x]=true;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;++i)
    	{
    		int a,b;
    		scanf("%d%d",&a,&b);
    		add(a,b);
    		add(b,a);
    	}
    	for(int i=1;i<=n;++i)
    	if(!DFN[i])tarjan(i,i);
    	int ans=0;
    	for(int i=1;i<=n;++i)
    	if(judge[i])ans++;printf("%d
    ",ans);
    	for(int i=1;i<=n;++i)
    	if(judge[i])printf("%d ",i);
    	return 0;
    }
    

    By njc

  • 相关阅读:
    matlab二维绘图学习摘要
    linux下有名管道进程通信
    《编写可读代码的艺术》第10章 抽取不相关的子问题
    《编写可读代码的艺术》第9章 变量可读性
    《编写可读代码的艺术》第8章 拆分超长的表达式
    《编写可读代码的艺术》第7章 简化循环和逻辑
    《编写可读代码的艺术》第6章 写出言简意赅的注释
    《编写可读代码的艺术》第5章 该写什么样的注释
    《编写可读代码的艺术》第4章 审美
    《编写可读代码的艺术》第3章 不会误解的名字
  • 原文地址:https://www.cnblogs.com/mudrobot/p/13329335.html
Copyright © 2011-2022 走看看