强连通分量 (kosaraju算法+tarjan算法)
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了强连通分量 (kosaraju算法+tarjan算法)相关的知识,希望对你有一定的参考价值。
数组都开得我麻木了。。。。
P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G
https://www.luogu.com.cn/problem/P2341
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m,head[maxn],cnt,dfn[maxn],low[maxn],bl[maxn],tim;
int inq[maxn],v[maxn],nxt[maxn],tol,in[maxn],ans,du[maxn];
stack<int>q;
void add(int u,int v1)
v[++cnt]=v1;
nxt[cnt]=head[u];
head[u]=cnt;
void tarjan(int u)
dfn[u]=low[u]=++tim;
q.push(u);
inq[u]=1;
for(int i=head[u];i;i=nxt[i])
int v1=v[i];
if(!dfn[v1])
tarjan(v1);
low[u]=min(low[u],low[v1]);
else if(inq[v1])
low[u]=min(low[u],dfn[v1]);
if(dfn[u]==low[u])
tol++;int tmp;
do
tmp=q.top();
q.pop();
inq[tmp]=0;
in[tol]++; //此强连通分量的点点数
bl[tmp]=tol; //缩点操作
while(tmp!=u);
int main()
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
int u,v1;scanf("%d%d",&u,&v1);
add(u,v1);
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
for(int f=1;f<=n;f++)
for(int i=head[f];i;i=nxt[i])
int vv=v[i];
if(bl[f]!=bl[vv])
du[bl[f]]++;
int tt=0;
for(int i=1;i<=tol;i++)
if(!du[i])
if(tt)
cout<<0<<endl;
return 0;
tt=i; //只能一个点出度为0
cout<<in[tt]<<endl;
return 0;
P2863 [USACO06JAN]The Cow Prom S
https://www.luogu.com.cn/problem/P2863
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int n,m,g[2][maxn],v[2][maxn],nxt[2][maxn],tmp,cnt,cc,q[maxn],f[maxn],t,ans;
bool vis[maxn];
void add(int u,int vv)
v[0][++cnt]=vv;
nxt[0][cnt]=g[0][u];
g[0][u]=cnt;
void add1(int u,int vv)
v[1][++cc]=vv;
nxt[1][cc]=g[1][u];
g[1][u]=cc;
void dfs1(int x)
vis[x]=1;
for(int i=g[0][x];i;i=nxt[0][i])
if(!vis[v[0][i]])
dfs1(v[0][i]);
q[++t]=x;
void dfs2(int x,int y)
vis[x]=0;f[x]=y;
tmp++;
for(int i=g[1][x];i;i=nxt[1][i])
if(vis[v[1][i]])
dfs2(v[1][i],y);
int main()
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
int u,vv;scanf("%d%d",&u,&vv);
add(u,vv);
add1(vv,u);
for(int i=1;i<=n;i++)
if(!vis[i])
dfs1(i);
for(int i=n;i>=1;i--)
tmp=0;
if(vis[q[i]])
dfs2(q[i],q[i]);
if(tmp>1)
ans++;
cout<<ans<<endl;
return 0;
https://www.luogu.com.cn/problem/P2835
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,head[maxn],cnt,dfn[maxn],low[maxn],bl[maxn],tim;
int inq[maxn],v[maxn],nxt[maxn],tol,in[maxn],ans;
stack<int>q;
void add(int u,int v1)
v[++cnt]=v1;
nxt[cnt]=head[u];
head[u]=cnt;
void tarjan(int u)
dfn[u]=low[u]=++tim;
q.push(u);
inq[u]=1;
for(int i=head[u];i;i=nxt[i])
int v1=v[i];
if(!dfn[v1])
tarjan(v1);
low[u]=min(low[u],low[v1]);
else if(inq[v1])
low[u]=min(low[u],dfn[v1]);
if(dfn[u]==low[u])
tol++;int tmp;
do
tmp=q.top();
q.pop();
inq[tmp]=0;
bl[tmp]=tol;
while(tmp!=u);
int main()
scanf("%d",&n);
for(int i=1;i<=n;i++)
int v1;
while(scanf("%d",&v1)&&v1)
add(i,v1);
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
for(int u=1;u<=n;u++)
for(int i=head[u];i;i=nxt[i])
if(bl[u]!=bl[v[i]])
in[bl[v[i]]]++;
for(int i=1;i<=tol;i++)
if(!in[i])
ans++;
cout<<ans<<endl;
return 0;
P2002 消息扩散
https://www.luogu.com.cn/problem/P2002
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int n,m,head[maxn],cnt,dfn[maxn],low[maxn],tim;
int inq[maxn],v[maxn],nxt[maxn],tol,ans,du[maxn],bl[maxn],in[maxn];
stack<int>q;
void add(int u,int v1)
v[++cnt]=v1;
nxt[cnt]=head[u];
head[u]=cnt;
void tarjan(int u)
dfn[u]=low[u]=++tim;
q.push(u);
inq[u]=1;
for(int i=head[u];i;i=nxt[i])
int v1=v[i];
if(!dfn[v1])
tarjan(v1);
low[u]=min(low[u],low[v1]);
else if(inq[v1])
low[u]=min(low[u],dfn[v1]);
if(dfn[u]==low[u])
tol++;int tmp;
do
tmp=q.top();
q.pop();
inq[tmp]=0;
in[tmp]=tol;
while(tmp!=u);
int main()
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
int u,v1;scanf("%d%d",&u,&v1);
add(u,v1);
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
for(int f=1;f<=n;f++)
for(int i=head[f];i;i=nxt[i])
int vv=v[i];
if(in[f]!=in[vv])
du[in[vv]]++;
for(int i=1;i<=tol;i++)
if(!du[i]) ans++;
cout<<ans<<endl;
return 0;
以上是关于强连通分量 (kosaraju算法+tarjan算法)的主要内容,如果未能解决你的问题,请参考以下文章
连通图算法详解之① :Tarjan 和 Kosaraju 算法
请问如何求(有向/无向)图的强连通分量,还有,基础一点,怎么求有几个连通图啊