什么是前向星呢?

我们在存一张图时,常用的方法有邻接表,邻接矩阵等。但图论的题的顶点数往往达到104级别或以上,这就意味着我们不能用邻接矩阵来存储,而邻接表也只能开动态数组,非常耗时。因此我们引入前向星。

在图中,我们往往会建立点集数组,但同样,我们也可以建立边集数组。保存每一条边的两个端点编号和边权即可。然后我们以起始端点为第一关键字,指向端点为第二关键字排序,这样,以同一个节点起始的边就被放在一起了。所谓前向星就是指建立一个边集的索引,包括起始端点i在排序后的边集数组中首次出现的位置head[i]和以i为起始端点的边的数目len[i],这样,我们再访问时,就可以像邻接表一样访问了。

那什么是链式前向星呢?

类比链表,链式前向星是不需要排序的,我们维护这样的一个边集数组:

1 struct Edge{
2     int to;//该边指向的节点
3     int value;//边权
4     int next;//起始端点相同的下一条边的编号
5 }edge[MAXM];

以及索引目录head[i](起始端点为i的第一条边,初始化为-1)

以下面最大流的前置重贴标签算法为例:

 1 #include<iostream>
 2 #include<iomanip>
 3 #include<ctime>
 4 #include<climits>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<vector>
 8 #include<cstring>
 9 #include<cstdio>
10 #include<cstdlib>
11 #include<map>
12 using namespace std;
13 typedef unsigned long long LL;
14 #define rep(i,a,b) for(int i=a;i<=b;i++)
15 #define dep(i,a,b) for(int i=a;i>=b;i--)
16 inline int read(){
17     int x=0;char ch=getchar();
18     while(ch<'0'||ch>'9'){
19         ch=getchar();
20     }
21     while(ch>='0'&&ch<='9'){
22         x=x*10+ch-'0';
23         ch=getchar();
24     }
25     return x;
26 }
27 
28 const int MAXN=10001,MAXM=100001;
29 int to[MAXM],next[MAXM],value[MAXM];//链式前向星的三个要素
30 int head[MAXN],h[MAXN]={0},e[MAXN],cnt=0;
31 void _insert(int u,int v,int w){//加边
32     to[cnt]=v;
33     value[cnt]=w;
34     next[cnt]=head[u];
35     head[u]=cnt++;
36     to[cnt]=u;//构建反向边(正反向边可以通过异或1得到)
37     value[cnt]=0;
38     next[cnt]=head[v];
39     head[v]=cnt++;
40 }
41 int main(){
42     int n=read(),m=read(),s=read(),t=read();
43     memset(head,-1,sizeof(head));
44     rep(i,1,m){
45         int u=read(),v=read(),w=read();
46         _insert(u,v,w);
47     }
48     h[s]=n;
49     e[s]=INT_MAX;
50     int ans=0,f;
51     queue<int>q;
52     for(int i=head[s];i!=-1;i=next[i]){//链式前向星标准访问循环
53         if(f=value[i]){
54             value[i^1]=f;
55             value[i]=0;
56             e[s]-=f;
57             e[to[i]]=f;
58             if(to[i]==t)ans+=f;else q.push(to[i]);
59         }
60     }
61     while(!q.empty()){
62         int u=q.front();q.pop();
63         while(e[u]){
64             int MIN=INT_MAX;
65             for(int i=head[u];i!=-1;i=next[i]){
66                 if(!value[i]||h[u]>h[to[i]]+1)continue;
67                 if(h[u]==h[to[i]]+1){
68                     int f=min(value[i],e[u]);
69                     e[u]-=f;
70                     e[to[i]]+=f;
71                     value[i]-=f;
72                     value[i^1]+=f;
73                     if(to[i]==t)ans+=f;
74                     else if(to[i]!=s)q.push(to[i]);
75                 }
76                 else MIN=min(MIN,h[to[i]]);
77             }
78             if(e[u])h[u]=MIN+1;
79         }
80     }
81     cout<<ans<<endl;
82     return 0;
83 }