图论基础算法

来源:互联网 发布:软件项目介绍书 编辑:程序博客网 时间:2024/05/16 10:16

这些东西本来去年就会的……然而由于太久没打(其实真相是整天都在浪),于是在某一天我惊奇地发现早已忘记……

首先,是有向图的强连通分量……我写的是tarjan算法(卧槽tarjan这人怎么这么6,splay,lca,强连通分量都跟他有关系)

这里有一道题目:codevs 2822(顺手把一年前没a的题a了)

强连通分量中边只有三种,一种是树边,一种是返祖边,还有一种不知道叫什么边(反正这种边都没用)

显然只有树边和返祖边有用

对于一个节点,他的颜色可能有三种,黑白灰,白表示这个节点还没有被访问过,灰表示在栈里,黑表示已出栈

我们需要两个数组:low数组用来记录他的子树的返祖边指向深度最浅的祖先的深度,dfn表示他的编号(也叫时间戳)

low(u)=

min{

dfn(u)

low(v) (u,v)为树边

dfn(v) (u,v)为返祖边

}

如果满足low(u)==dfn(u)那么说明u和当前栈里还没出栈的深度比u深的节点都属于一个强连通分量

什么?无向图的双连通分量?

一样的……只要记录上一个节点防止死循环就好了……

割点:把这个点去掉之后连通分量数量增加

桥:把这条边去掉之后连通分量数量增加

割点求法:有两种情况

1,根有超过两棵子树,此时根为割点

2,存在树边u,v,使得low(v)>=dfn(u)

桥求法:树边u,v,使得low(v)>dfn(u)

割点例题:poj1174

桥例题:hdu4738

强连通分量code:

void dfs(int now)

{

s.push(now);
low[now]=dfn[now]=++tot;
vis[now]++;
for (int ii=0;ii<g[now].size();ii++) if (!vis[g[now][ii]]){
dfs(g[now][ii]);
low[now]=min(low[now],low[g[now][ii]]);
}
else if (vis[g[now][ii]]==1){
low[now]=min(low[now],dfn[g[now][ii]]);
}
if (low[now]==dfn[now]){
if (!s.empty()){
int jb=s.top();s.pop();
ans++;
while (jb!=now){
fa[jb]=ans;
size[ans]++;
vis[jb]++;
jb=s.top();s.pop();
}
fa[jb]=ans;
size[ans]++;
vis[jb]++;
}
}
}

0 0
原创粉丝点击