题目大意十分简单,就是给你m条边的距离,让你求从1到n的最短路径.
解题思路:这是我第一次用spfa算法解题,学习spfa算法的心得都在代码注释里,若理解不对还请大牛们指出,谢谢啦。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; #define inf 1<<29 typedef struct Node { int c; int u; int v; }; Node nodes[4005]; int head[1005],next[4005],dist[1005]; bool visited[1005]; int num[1005];//用来判断是否存在负环,如果一个顶点入队超过n的话就说明有负环 int n,m; int a1,a2,a3,e,sum; void add_node(int u,int v,int c) { nodes[e].u=u; nodes[e].v=v; nodes[e].c=c; next[e]=head[u]; //在这里可以解释为什么spfa算法可以避免重边 head[u]=e; //因为这里是将节点插入到起始节点之前,若有重边,则会查到原来已经插入的节点的前面 e++; } bool relax(int u,int v,int c) { if(dist[v]>dist[u]+c) { dist[v]=dist[u]+c; return true; } return false; } bool spfa() { queue<int>que; for(int i=2;i<=n;i++) { dist[i]=inf; } dist[1]=0;visited[1]=true; que.push(1); while(!que.empty()) { int q=que.front(); que.pop(); visited[q]=false; for(int i=head[q];i+1;i=next[i])//从q的头结点开始不断地往该邻接表的下一节点进行遍历 { //若节点有更新则入队并标记为true,因为最短路肯定是由上一个被更新的节点得来的 if(relax(q,nodes[i].v,nodes[i].c)&&!visited[nodes[i].v])//注意这里一定要先松弛,在进行标记判断 {//因为有可能这个点已经被松弛过并入队列了,但找到一个更好的点到该点的距离更短,那也需要进行松弛 if(++num[nodes[i].v]>n) //说明存在负环 return false; que.push(nodes[i].v);//没有负环则入队列 visited[nodes[i].v]=true; } } } return true; } int main() { while(scanf("%d%d",&m,&n)!=EOF) { sum=0; e=1; memset(nodes,0,sizeof(nodes)); memset(head,-1,sizeof(head)); memset(next,-1,sizeof(next)); memset(visited,false,sizeof(visited)); for(int i=0;i<m;i++) { scanf("%d%d%d",&a1,&a2,&a3); add_node(a1,a2,a3);//因为是无向边,因此要加两次节点 add_node(a2,a1,a3); } spfa(); printf("%d\n",dist[n]); } return 0; }