Spfa模板(使用邻接表和队列实现)

Spfa模板(使用邻接表和队列实现)

全局准备工作

int N, X;    //N为点数 X为源点
int head[MAXN];    //head[src]表示以head为出发点的邻接表表头在数组Adj中的位置,开始时所有元素初始化为-1
int nodeP;    //在邻接表和指向表头的head数组中定位用的记录指针,开始时初始化为0
int dist[MAXN];    //储存到源节点的距离,在Spfa()中初始化
bool vis[MAXN];    //这里vis作inqueue解释会更好,出于习惯使用了vis来命名,在Spfa()中初始化

Node定义

struct Node {
    int v, w, next;
}Adj[MAXM];

v即vertex,这里意思相当于被指向的点to,w相当于weight,代表边权,next用来指向在Adj中下一个从相同src出发的边指向的点

addEdge函数

void addEdge(int src, int to, int weight)
{
    Adj[nodeP].v = to;
    Adj[nodeP].w = weight;
    Adj[nodeP].next = head[src];
    head[src] = nodeP++;
}

addEdge(a, b, w)作用是在数组Adj中留下一条记录了去向和边权的记录,且其next指向表中相同src指向的下一个点,同时更新了head表头

Spfa主体

void Spfa()
{
    queue<int> que;
    int i;
    for(i = 1; i <= N; i++) {
        dist[i] = NIL;
        vis[i] = false;
    }
    dist[X] = 0;	//X为源点
    que.push(X);
    while(!que.empty()) {
        int now = que.front();
        que.pop();
        vis[now] = false;	//从queue中退出
	//遍历邻接表
        for(i = head[now]; i != -1; i = Adj[i].next) {	//在Adj中,相同src出发指向的顶点为从head[src]开始的一项,逐项使用next寻找下去,直到找到第一个被输
                                                        //入的项,其next值为-1
            int to = Adj[i].v;				
            if(dist[to] == NIL || dist[to] > dist[now] + Adj[i].w) {	//松弛(RELAX)操作
                dist[to] = dist[now] + Adj[i].w;
                if(!vis[to]) {	//若被搜索到的节点不在队列que中,则把to加入到队列中去
                    vis[to] = true;
                    que.push(to);
                }
            }
        }
    }
}
 

main中初始化

  1. int main()
    {
        memset(head, -1, sizeof(head));
        ... 
       while(...) {
        	cin >> a >> b >> c;
        	addEdge(a, b, c);
        }
        Spfa();
        //结果已经储存在dist数组中
        return 0;
    }
    
    扫描二维码关注公众号,回复: 2859752 查看本文章

有些人以为这个算法是Dijkstra,事实上Spfa和Dijkstra很像,只是他们维护的队列不同,Spfa维护的是一个初始只有源节点的队列,而Dijkstra要维护初始为所有顶点的队列。

猜你喜欢

转载自blog.csdn.net/Strive_Y/article/details/81711064