您的位置:首页 > 其它

一个我认为比较好的Spfa模板(使用邻接表和队列实现)

2015-05-16 22:02 162 查看
全局准备工作
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中初始化
int main()
{
memset(head, -1, sizeof(head));
... 
while(...) {
cin >> a >> b >> c;
addEdge(a, b, c);
}
Spfa();
//结果已经储存在dist数组中
return 0;
}
有些人以为这个算法是Dijkstra,事实上Spfa和Dijkstra很像,只是他们维护的队列不同,Spfa维护的是一个初始只有源节点的队列,而Dijkstra要维护初始为所有顶点的队列。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: