模板:
加边:
struct node{
int to,next,w;
}edge[1000];
int head[1000],cnt;
void add(int u,int v,int w)
{
++cnt;
edge[cnt].to = v;
edge[cnt].next = head[u];
edge[cnt].w = w;
head[u] = cnt;
}
e[i].to是指第i条边的终点,e[i].next是指与第i条边同起点(即u)的下一条边的储存下标(0时退出),e[i].w即第i条边的权重,head[u]是指u为起点的存储下标。
遍历:(遍历以u为起点的边)
for(i=head[u];i;i=edge[i].next)
i开始为第一条边,每次指向下一条(以0为结束标志) (若下标从0开始,next应初始化-1)
假设输入1 2; 1 3; 1 5,即head一直更新,head[1] = 1;head [1] = 2;head[1] = 3,访问时其实是倒着访问的,先访问edge[3],然后i更新为edge[i].next即前一个head[1]即2,访问edge[2],再然后i更新为1,访问edge[1]。
推荐博客:https://blog.youkuaiyun.com/Binary_Heap/article/details/78209086
比较详细,也有SPFA的拓展。
Trajan算法
int number[M],low[M],color[M],scc,cnt; //萌新手打,请勿使用
stack<int> s;
void dfs(int u)
{
s.push(u) //点入栈
number[u]=low[u]=++cnt; //时间戳
int v;
for(i=head[u];i;i=edge[i].next)
{
v=edge[i].to;
if(!number[v]) //点v有没有访问过,没有就从这里dfs
{
dfs(v);
low[u]=min(low[u],low[v]);
}
else if(!color[u]) //或者(number[v]<number[u]) 意思是有反向边
{
low[u]=min(low[u],number[v]);
}
}
if(number[u]==low[u])
{
int x;
++scc; //强连通分量个数
while(true)
{
x=s.pop();
color[x]=scc; //同scc对应同一个强分量;
size_[scc]++; //一个强连通分量的点的个数
if(u==x) break;
}
}
}
Trajan算法求强连通数,缩点,割点。
number[]是指访问的点的标号,low[]是指能到达或者子代能到达的最早结点标号,color[]标记同一个强连通分量,size_[]是一个强连通分量的点的个数。scc即强连通分量个数。
另附大佬理解:https://blog.youkuaiyun.com/mengxiang000000/article/details/51672725