图论 __ 链式前向星
概括
以同起点为一条链,数组head[a]存储起点a的最新录入的一条边的索引,每条边以结构体的形式存储该边信息(该边终点,权值,同起点的边中的上一条边即上一次录入的边的位置),所有边构成一个结构体数组。
很多帖子说到的是存储的是下一条边,这种理解很容易给人误导,应该是每一条边都能通过自身结构体存储的信息回溯到上一条边,所以叫前向星。
假如我们要找出一条a -> b的边,先根据head[a]找出从起点a出发的所有边里最新录入的那条边,然后根据该边找出它的上一条边,再根据上一条边找出它的上上一条边……直到找到一条终点为b的边为止。整个过程是链式回溯的,所以是链式前向星。
看完一脸懵? 没关系,直接看下面示范即可
范例
边的录入顺序(起点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;
}