循环的提前跳出:在实际操作中,贝尔曼-福特算法经常会在未达到V-1次前就出解,V-1其实是最大值。于是可以在循环中设置判定,在某次循环不再进行松弛时,直接退出循环,进行负权环判定。
具体做法是用一个队列保存待松弛的点,然后对于每个出队的点依次遍历每个与他有边相邻的点(用邻接表效率较高),如果该点可以松弛并且队列中没有该点则将它加入队列中(只有进行松弛操作的点才会对它的邻接点有影响,也就是说其邻接点才需要松弛操作),如此迭代直到队列为空。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 105
#define MAXN 1005
using namespace std;
int n,m,ans,cnt,sx;
bool vis[maxn];
int dist[maxn],p[maxn];
struct Node
{
int r,cost,next;
}edge[MAXN];
void init()
{
memset(vis,0,sizeof(vis));
memset(p,0,sizeof(p));
memset(dist,0x3f,sizeof(dist));
}
void addedge(int u,int v,int w)
{
cnt++;
edge[cnt].r=v;
edge[cnt].cost=w;
edge[cnt].next=p[u];
p[u]=cnt;
}
void SPFA()
{
int i,j,nx;
sx=1;
queue<int>q;
dist[sx]=0;
vis[sx]=1;
q.push(sx);
while(!q.empty())
{
nx=q.front();
vis[nx]=0;
q.pop();
for(i=p[nx];i;i=edge[i].next)
{
if(dist[edge[i].r]>dist[nx]+edge[i].cost)
{
dist[edge[i].r]=dist[nx]+edge[i].cost;
if(!vis[edge[i].r])
{
vis[edge[i].r]=1;
q.push(edge[i].r);
}
}
}
}
}
int main()
{
int i,j,u,v,w;
while(~scanf("%d%d",&n,&m))
{
init();
cnt=0;
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
SPFA();
for(i=1;i<=n;i++)
printf("i:%d dist:%d\n",i,dist[i]);
}
return 0;
}
7 9
1 2 3
2 4 1
3 4 4
4 6 2
3 6 8
6 7 5
4 5 6
5 7 7
1 3 2