图论 __ 链式前向星

原文

概括

以同起点为一条链,数组head[a]存储起点a的最新录入的一条边的索引,每条边以结构体的形式存储该边信息(该边终点,权值,同起点的边中的上一条边即上一次录入的边的位置),所有边构成一个结构体数组。

很多帖子说到的是存储的是下一条边,这种理解很容易给人误导,应该是每一条边都能通过自身结构体存储的信息回溯到上一条边,所以叫前向星。

假如我们要找出一条a -> b的边,先根据head[a]找出从起点a出发的所有边里最新录入的那条边,然后根据该边找出它的上一条边,再根据上一条边找出它的上上一条边……直到找到一条终点为b的边为止。整个过程是链式回溯的,所以是链式前向星。

看完一脸懵? 没关系,直接看下面示范即可

范例

image

边的录入顺序(起点a -> 终点b = 权值w):

第0条边:5 -> 3 = 1  此时head[5]=0  以5为起点没有上一条边
第1条边:1 -> 2 = 9  此时head[1]=1  以1为起点没有上一条边
第2条边:3 -> 5 = 11  此时head[3]=2  以3为起点没有上一条边
第3条边:2 -> 1 = 5  此时head[2]=3  以2为起点没有上一条边
第4条边:4 -> 5 = 6  此时head[4]=4  以4为起点没有上一条边
第5条边:3 -> 1 = 7  此时head[3]=5  以3为起点的上一条边的是第2条边
第6条边:3 -> 4 = 4  此时head[3]=6  以3为起点的上一条边的是第5条边
第7条边:4 -> 1 = 2  此时head[4]=7  以4为起点的上一条边的是第4条边

假如我们要找3 -> 5这条边:

根据head[3]=6,得到起点3的最新一条录入的边是第6条边
根据edge[6].to=4,这条是3 -> 4的边,不符合,我们继续找
根据edge[6].pre=5,得到第6条边的上一条同起点边是第5条边
根据edge[5].to=1,这条是3 -> 1的边,不符合,我们继续找
根据edge[5].pre=2,得到第5条边的上一条同起点边是第2条边
根据edge[2].to=5,这条是3 -> 5的边,找到了

代码实现

边的结构体

存储该边信息

struct Edge{
    int to;//表示该边的终点
    int pre;//同起点的上一条边的位置,值为-1表示没有上一条边
    int w;//该边权值 
};
//定义结构体数组edge,存储每一次录入的边
Edge edge[2*m+2];

定义链头head

存储每个起点的最新一条边的索引,-1表示该点无边

int head[n+1];
memset(head,-1,sizeof(head));

定义一个边的计数器

,表示当前已录入边的数量

int ecnt=0;

增边函数

增加一条a -> b的权值为w的边。

inline void addEdge(int a,int b,int w,int head[],Edge edge[],int &ecnt){
    edge[ecnt].w=w;
    edge[ecnt].to=b;
    edge[ecnt].pre=head[a];//该边上浮为起点a的所有边里最新的边 
    head[a]=ecnt++;
}

增边函数,只能是有向边,对于无向边再增加一次反向边即可。

addEdge(a,b,w,head,edge,ecnt);
addEdge(b,a,w,head,edge,ecnt);

模板代码

int h[N], to[N], pre[M], idx;
void add(int a, int b)
{
  to[idx] = b, pre[idx] = h[a], h[a] = idx++;
}
signed main()
{
  memset(head, -1, sizeof(head));
  return 0;
}
posted @ 2022-07-13 11:14  kingwzun  阅读(29)  评论(0编辑  收藏  举报