您的位置:首页 > 其它

强联通分量——学习笔记

2017-08-02 22:26 183 查看
温馨提示:接下来讨论的情况全部建立在有向图的基础上。

如果两个点i,j满足i能到j且j能到i,则i和j强联通。所有点都强连通的图是强连通图,一个有向图中的所有最大(就是不能再扩大了)的强连通子图都是这个有向图的强连通分量。强联通分量貌似除了环缩点也没别的作用了。求有向图中的强联通分量可以用Tarjan算法,用递归的方法。复杂度为O(n);

Tarjan的核心就是两个数组dfn和low,其中dfn[i]是i的访问时刻,用一个time(官方说法叫时间戳,并不明白是啥么玩意儿),而low[i]表示i能追溯到的最早时刻。

接着再开一个栈stk,表示目前处理的强连通分量中的点。访问一个点i时,先进行初始化dfn[i]=low[i]v=++ti,然后枚举i的儿子节点们,假设目前处理的i的儿子是son,那么分为两种情况

1.sin还没访问过,然后先访问,然后就追溯到low[son],所以这时low[i]=min(low[i],low[son]);

2.son已访问,此时再分两种

(1) son不在栈里,就表示和i没什么关系了.

(2)son还在栈里,这时用子树节点更新节点第一次出现的时间low[i]=min(low[i],dfn[son]);

给个题 BZOJ 1179 抢掠计划

经典的tarjan环缩点假spfa刷最长路。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 500005
using namespace std;
int n,e,m,s,tot[2],tem,sum,top,a[maxn],b[maxn],fa[maxn],lnk[2][maxn],son[2][maxn],nxt[2][maxn],low[maxn],dfn[maxn],stk[maxn],dst[maxn],que[maxn];
bool instk[maxn],vs[maxn];
inline void readi(int &x){
x=0; char ch=getchar();
while ('0'>ch||ch>'9') ch=getchar();
while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
}
void _add(int t,int x,int y){
tot[t]++;
son[t][tot[t]]=y; nxt[t][tot[t]]=lnk[t][x]; lnk[t][x]=tot[t];
}
void _dfs(int x){
dfn[x]=low[x]=++tem; instk[x]=true; stk[++top]=x;
for (int j=lnk[0][x];j;j=nxt[0][j]){
if (!dfn[son[0][j]]) {_dfs(son[0][j]); if (low[x]>low[son[0][j]]) low[x]=low[son[0][j]];}
else if (instk[son[0][j]]&&low[x]>dfn[son[0][j]]) low[x]=dfn[son[0][j]];
}
if (dfn[x]!=low[x]) return;
int y; sum++;
do{
y=stk[top--]; fa[y]=sum; instk[y]=false; b[sum]+=a[y];
}while (x!=y);
}
void _spfa(){
memset(vs,0,sizeof(vs));
memset(dst,192,sizeof(dst));
int hed=0,til=1; que[1]=fa[s]; vs[fa[s]]=true; dst[fa[s]]=b[fa[s]];
while (hed!=til){
hed=(hed+1)%maxn;
vs[que[hed]]=false;
for (int j=lnk[1][que[hed]];j;j=nxt[1][j]){
if (dst[son[1][j]]<dst[que[hed]]+b[son[1][j]]){
dst[son[1][j]]=dst[que[hed]]+b[son[1][j]];
if (!vs[son[1][j]]){
til=(til+1)%maxn;
que[til]=son[1][j];
vs[son[1][j]]=true;
if (dst[son[1][j]]>dst[que[(hed+1)%maxn]]) swap(que[til],que[(hed+1)%maxn]);
}
}
}
}
}
int main()
{
readi(n); readi(e); tot[0]=tot[1]=0;
memset(lnk,0,sizeof(lnk));
memset(nxt,0,sizeof(nxt));
for (int i=1;i<=e;i++){
int x,y; readi(x); readi(y); _add(0,x,y);
}
for (int i=1;i<=n;i++) readi(a[i]);
tem=sum=top=0;
memset(b,0,sizeof(b));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(stk,0,sizeof(stk));
memset(instk,0,sizeof(instk));
for (int i=1;i<=n;i++) if (!dfn[i]) _dfs(i);
//  for (int i=1;i<=n;i++) printf("%d ",fa[i]); printf("\n");
for (int i=1;i<=n;i++)
for (int j=lnk[0][i];j;j=nxt[0][j]) if (fa[i]!=fa[son[0][j]]) _add(1,fa[i],fa[son[0][j]]);
readi(s); _spfa(); readi(m); int ans=0;
//  for (int i=1;i<=sum;i++) printf("%d ",dst[i]); printf("\n");
for (int i=1;i<=m;i++){
int p; readi(p);
if (ans<dst[fa[p]]) ans=dst[fa[p]];
}
printf("%d",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: