Dijkstra+heap是用小根堆,每次取出d最小的点,来更新距离,那么这个点来说,最小距离就是当前的d。
SPFA是用双端队列,每次取出队头,来更新距离,它之后可能还会入队。它是一种动态逼近法,因为每次松弛距离都会减小,所以松弛一定会有结束的。如果一个点入队超过n次就是存在负环。
SPFA用于稀疏图和存在负权的图
#include<bits/stdc++.h>
using namespace std;
const int nmax=1005,emax=5005;
struct pp
{
int v, w, next;
}edge[2*emax]; // 无向边
bool vis[nmax];
int head[nmax],num[nmax],n,m,cnt=0;
long long dist[nmax]; //注意dist范围和内存限制;
void add(int t1,int t2,int t3)
{
edge[++cnt].v=t2;
edge[cnt].w=t3;
edge[cnt].next=head[t1];
head[t1]=cnt;
}
int spfa(int start)
{
long long sum=0;
int cnt_q=1; //统计队列中的数量
memset(vis,0,sizeof(vis));
memset(dist,0x3f3f3f3f3f3f3f3f,sizeof(dist));//int 0x3f3f3f3f
deque<int> q;//STL中的双端队列 可在两端实现入队出队
vis[start]=1;
dist[start]=0;
num[start]++;
q.push_back(start);
while(!q.empty())
{
int temp= q.front();q.pop_front();//每次从前端取出
//LLL,未验证,如无特殊需求,删掉if这一段
if(dist[temp]*cnt_q>sum)//注意dist[temp]*cnt_q不要超范围
{
q.push_back(temp);
continue;
}
sum -=dist[temp];cnt_q--;
vis[temp]=0;
for(int i=head[temp];i;i=edge[i].next)
{
int v=edge[i].v;
if(dist[temp]+edge[i].w<dist[v])
{
dist[v]=dist[temp]+edge[i].w;
if(!vis[v])
{
vis[v]=1;
num[v]++;
if(num[v]==n)return 0;//判断是否有负环存在
if(!q.empty())
{
if(dist[v]>dist[q.front()])//距离大的往后端放
q.push_back(v);
else q.push_front(v);//小的放前端
}
else q.push_back(v);
sum +=dist[v];cnt_q++;
}
}
}
}
return 1;
}
int main()
{
int t1,t2,t3;
cin>>n>>m;
while(m--)
{
scanf("%d%d%d",&t1,&t2,&t3);
add(t1,t2,t3);
add(t2,t1,t3);
}
if(spfa(1))
cout<<dist[n]<<endl;
return 0;
}