Problem:
已知
n
n
n个点,
n
n
n条有向边,求最小的强联通分量大小。
Solution:
方法一:拓扑排序
拓扑排序可以维护点之间的拓扑关系并打上标记,那么没有打标记的点就一定在某个强联通分量中,枚举没有标记的点进行查找即可求出最小强联通分量大小。
#include <stdio.h>
#include <algorithm>
#define M 200000+5
using namespace std;
struct abcd{
int to, next;
}edge[M];
void Addedge(int x, int y);
void Topology_Sort();
int n, Min = 200000+5, i, j, a, head[M];
int cnt[M], q[M], r, h, ans, tot;
bool v[M];
int main()
{
scanf("%d", &n);
for(i = 1; i <= n; i++){
scanf("%d", &a);
Addedge(i, a);
cnt[a]++;
}
Topology_Sort();
printf("%d", Min);
return 0;
}
void Addedge(int x, int y){
edge[++tot].to = y;
edge[tot].next = head[x];
head[x] = tot;
}
void Topology_Sort(){
for(i = 1; i <= n; i++)
if(!cnt[i])
q[++r] = i;
while(r != h){
int x = q[++h];
v[x] = true;
if(!--cnt[edge[x].to])
q[++r] = edge[x].to;
}
for(i = 1; i <= n; i++){
if(!v[i]){
v[i] = true;
int level = 1;
for(j = i; !v[edge[j].to]; j = edge[j].to){
v[edge[j].to] = true;
level++;
}
if(level < Min)
Min = level;
}
}
}
方法二:
t
a
r
j
a
n
tarjan
tarjan求强联通分量
t
a
r
j
a
n
tarjan
tarjan维护出强联通分量,其中
s
i
z
e
>
1
size>1
size>1的属于合法强联通分量,更新答案即可。
#include <stdio.h>
#include <algorithm>
using namespace std;
int n,t,ans=~0u>>1;
struct Data
{
int to,next;
}edge[200001];
int head[200001],tot;
void insert(int x,int y)
{
edge[++tot].to=y;
edge[tot].next=head[x];
head[x]=tot;
}
int vis[200001],top,cnt,scc,size[200001];
int stack[200001],dfn[200001],low[200001],instack[200001];
void tarjan(int x)
{
stack[++top]=x;
vis[x]=1;
instack[x]=1;
dfn[x]=low[x]=++cnt;
for(int i=head[x]; i; i=edge[i].next)
{
if(!vis[edge[i].to])
{
tarjan(edge[i].to);
low[x]=min(low[x],low[edge[i].to]);
}
else if(instack[edge[i].to])
low[x]=min(low[x],dfn[edge[i].to]);
}
if(dfn[x]==low[x])
{
++scc;
int tt;
do
{
tt=stack[top--];
instack[tt]=0;
size[scc]++;
}while(tt!=x);
}
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&t);
insert(i,t);
}
for(int i=1; i<=n; i++)
if(!dfn[i])
tarjan(i);
for(int i=1; i<=scc; i++)
if(size[i]>1)
ans=min(ans,size[i]);
printf("%d",ans);
exit(0);
}