存储图可以用邻接表和邻接矩阵

以下代码来自 https://www.acwing.com/blog/content/405/

// 对于每个点k,开一个单链表,存储k所有可以走到的点。h[k]存储这个单链表的头结点
int h[N], e[N], ne[N], idx, w[N];

// 添加一条边a->b,权重是w
void add(int a, int b, int w)
{
    e[idx] = b, ne[idx] = h[a], w[idx] = w, h[a] = idx ++ ;
}

// 初始化
idx = 0;
memset(h, -1, sizeof h);

解释:
虽然是链表,但是没有用指针实现。实际上每条边都有一个编号(也就是idx),用编号来定位一条边,指向下一条边。

一个邻接表需要两种数据,一个是头结点,一种是边结点。头结点a指向边结点b,表示一条边a --> b

在这里头结点的结构是一个数组:i表示某点;h[i]是从i出发的一条边的编号,也就是指向了这条边。
边结点的结构:j表示某条边的编号;e[j]是这条边的终点;w[j]是这条边的权重;ne[j]是该结点指向的下一条边的编号。
idx是边的编号,和头结点一点关系都没有。

下面解释add函数的内容。这里使用的是头插法(实际上也不好用尾插法):

//插入一条a->b,权重为w的边
//处理边节点
e[idx] = b,w[idx] = w; //初始化边结点的终点和权重
ne[idx] = h[a];        //让新的边结点的next也指向h[a]指向的那条边
//处理头结点
h[a] = idx ++ ;        //让头结点指向新的边