您的位置:首页 > 其它

有向图双连通分量(tranjan算法) 总结

2015-07-10 17:15 302 查看
借鉴博客 点击打开链接

Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。

在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected)。

如果有向图G的每两个顶点都强连通,称G是一个强连通图。

非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。

POJ 2187

哪个节点是被其他所有节点都可以所达到的。

图有可能不是连通的。

也有可能重边。

构造一个有向无环图,那么只有出度为0并且只有一个出度为0的点才是

被所有节点所指向。

先把这个有向图的强通分量找出来。当成一个节点。在用上述方法做出来。

HDU 2767

每个公式都可以推导出其他公式,问添加几个证明可以让所有的公式互相推导出来。

补最少的边让这个图所有节点都可以互相到达。

用tranjan算法缩点之后

当一个有向图变成一个有向有环图,

就是所有的出度和入度不为0

一个出度可以和入度添加一条边完成,连通。

剩下来的点都可以用自己本身相同的数量的边完成。

HDU 1269

就是判断是不是全图是一个强连通分量。

HDU 1827

用打电话的方式通知到所有的人。

:当缩点之后,看看哪些点没有入度,就可以判断,他没有被联系到。

在把这个点的最少费用比较出来,然后跟所有的人比较一下。就可以。

HDU 3072

这道题的意思:现在需要从0通知到(n-1)个人。

每个通知的人都会有一个花费的代价。

但是现在有一种情况,如果有两个人可以互相联系到,则那个人只需要通知一个人

就可以,不用管它可以相互到达的另一个点。

思路就是:先缩点。

然后在将所有的路从新走一遍。找出一个点另一个点(有可能是一个块)最小代价。

如果一个点和另一个点是属于同一个强连通分量的就跳过。

然后就加上所有这种的代价,然后就好了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=100000*4;
int e,pnt[maxn],nxt[maxn],head[maxn];
int low[maxn],dfn[maxn],belong[maxn],st[maxn],panduan[maxn];
int n,m,top,cnt,depth;
//panduan[]判断这个点是否已成为一个单独的强连通分量。
//dfn这个数组是搜索的次序号,不是每一个点的编号。
//Tarjan算法是基于对图深度优先搜索的算法,
//每个强连通分量为搜索树中的一棵子树。搜索时
//把当前搜索树中未处理的节点加入一个堆栈,
//回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。
void AddEdge(int u,int v)
{
pnt[e]=v;
nxt[e]=head[u];
head[u]=e++;
}
void init()
{
e=0;
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
top=cnt=depth=0;
for(int i=1; i<=n; i++)
panduan[i]=belong[i]=0;
}
void dfs(int now)
{
printf("%d \n",now);
st[top++]=now;
dfn[now]=low[now]=++depth;
panduan[now]=1;
for(int i=head[now]; i!=-1; i=nxt[i])
{
if(!dfn[pnt[i]])
{
dfs(pnt[i]);
low[now]=min(low[now],low[pnt[i]]);
}
else if(panduan[pnt[i]])//遇到回边的处理,如果是之前已经处理过的强连通分量的点就不管了。
low[now]=min(low[now],dfn[pnt[i]]);
}
if(low[now]==dfn[now])
{
cnt++;
int j;
while(j=st[--top])
{
panduan[st[top]]=0;
belong[st[top]]=cnt;
if(j==now)break;
}
}
return ;
}

int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)break;
init();
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
AddEdge(u,v);
}
for(int i=1;i<=n;i++)
if(!dfn[i])
dfs(1);
for(int i=1;i<=n;i++)
printf("%d ",belong[i]);
puts("");
if(cnt>1)puts("No");
else puts("Yes");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: