总结一下spfa算法和dj算法区别
首先
1:dj算法开始的book都是0,而且当找到一个最小点,接下来松弛的操作,只是入队,而不将他们的book数组改变,改变book数组只在找到最小点的时候这一次而已
2;spfa算法不同,spfa其实就是bellman算法的强化版,他是现将起始点入队并且入队的标志就是book数组变为1,-----重点就是入队操作与book数组改变的操作一致----,队头元素对接下来的元素进行松
弛,如果找到一个,入队并且打上标志,-------再次申明,打上标志跟入队操作一致,出队也是一样!!
一道题目用spfa与dj算法来解此题的逆向思维很厉害,需要1到其她点的最短路,也需要其他点到1的最短路,而第二部只需要将所有点反过来再跑一边最短路即可
dj算法-用优先队列优化
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=2e4+10;
const int maxx=6e4+10;
int book[maxn];
int n,m;;
ll head[maxx],dist[maxn],cnt=0;
struct node
{
int to,next;
ll w;
} edge[maxx];
struct data
{
int x1,x2;
ll x3;
} a[maxx];
void add(int u,int v,ll z)
{
edge[cnt].to=v;
edge[cnt].w=z;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void dj(int s)
{
for(int i=1; i<=n; i++)
{
book[i]=0;
dist[i]=INF;
}
dist[s]=0;
//距离+顶点
priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > >q;
q.push(make_pair(0,s));
while(!q.empty())
{
int f=q.top().second;q.pop();
if(book[f])continue;
book[f]=1;
for(int i=head[f]; i!=-1; i=edge[i].next)
{
if(dist[edge[i].to]>dist[f]+edge[i].w&&!book[edge[i].to])
{
dist[edge[i].to]=dist[f]+edge[i].w;
// book[edge[i].to]=1;
q.push(make_pair(dist[edge[i].to],edge[i].to));
}
}
}
}
int main()
{
int T;
ios::sync_with_stdio(false);
cin>>T;
while(T--)
{
ll sum=0;
cnt=0;
cin>>n>>m;
for(int i=1; i<=n; i++)
head[i]=-1;
for(int i=0; i<m; i++)
{
cin>>a[i].x1>>a[i].x2>>a[i].x3;
add(a[i].x1,a[i].x2,a[i].x3);
}
dj(1);
for(int i=1; i<=n; i++)
sum+=dist[i];
//cout<<sum<<"-------------"<<endl;
cnt=0;
for(int i=1; i<=n; i++)
head[i]=-1;
for(int i=0; i<m; i++)add(a[i].x2,a[i].x1,a[i].x3);
dj(1);
for(int i=1; i<=n; i++)
sum+=dist[i];
cout<<sum<<endl;
}
return 0;
}
spfa算法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int maxn=2e4+10;
const int maxm=6e4+10;
int head[maxn],cnt,from[maxm],to[maxm];
int n,m;
bool vis[maxn];
ll dis[maxn],cost[maxm];
struct Edge
{
int u,v,next;
ll w;
} edge[maxm];
void addedge(int u,int v,ll w)
{
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void spfa(int s)
{
for(int i=1; i<=n; i++)
{
vis[i]=false;
dis[i]=inf;
}
queue<int> q;
q.push(s);
dis[s]=0;
vis[s]=true;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
if(dis[edge[i].v]>dis[u]+edge[i].w)
{
dis[edge[i].v]=dis[u]+edge[i].w;
if(!vis[edge[i].v])
{
vis[edge[i].v]=true;
q.push(edge[i].v);
}
}
}
}
}
int main()
{
int T;
ios::sync_with_stdio(false);
cin>>T;
while(T--)
{
cnt=0;
cin>>n>>m;
for(int i=1; i<=n; i++)
head[i]=-1;
for(int i=1; i<=m; i++)
{
cin>>from[i]>>to[i]>>cost[i];
addedge(from[i],to[i],cost[i]);
}
spfa(1);
ll ans=0;
for(int i=1; i<=n; i++)
ans+=dis[i];
cnt=0;
for(int i=1; i<=n; i++)
head[i]=-1;
for(int i=1; i<=m; i++)
addedge(to[i],from[i],cost[i]);
spfa(1);
for(int i=1; i<=n; i++)
ans+=dis[i];
cout<<ans<<endl;
}
return 0;
}
spfa朴素算法,检查是否有回路
#include<bits/stdc++.h>
using namespace std;
const int inf=999999;
int main()
{
int dis[10],u[10],v[10],w[10],check,flag,n,m;
cin>>n>>m;//n个顶点,m条边
for(int i=1; i<=m; i++)
cin>>u[i]>>v[i]>>w[i];
for(int i=1; i<=n; i++)
dis[i]=inf;
dis[1]=0;
for(int k=1; k<=n-1; i++)//最多进行n-1个阶段
{
check=0;
for(int i=1; i<=m; i++)//对每条边进行松弛操作
if(dis[v[i]]>dis[u[i]]+w[i])
{
dis[v[i]]=dis[u[i]]+w[i];
check=1;
}
if(check==0)break;//如果此次一次松弛操作也没进行就返回,因为此时dis已经达到极致
}
flag=0;
for(int i=1; i<=n; i++)
if(dis[v[i]]>dis[u[i]]+w[i])flag=1;
if(flag==1)cout<<"此图含有负权回路";
else for(int i=1; i<=n; i++)
cout<<dis[i]<<" ";
return 0;
}
Floyd算法---多源最短路
#include<bits/stdc++.h>
using namespace std;
const int inf=999999;
int main()
{
int e[10][10],k,n,m,t1,t2,t3;
cin>>n>>m;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(i==j)e[i][j]=0;
else e[i][j]=inf;
for(int i=1; i<=m; i++)
{
cin>>t1>>t2>>t3;
e[t1][t2]=t3;
}
//Floyd核心思想,用到了动态规划的思想,后面的可以用到前面的最小值,e[i][j]>e[i][k]+e[k][j] ,这样最多更新n次
//这为后面spfa算法做了铺垫
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(e[i][j]>e[i][k]+e[k][j])e[i][j]=e[i][k]+e[k][j];
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)cout<<e[i][j]<<" ";
cout<<endl;
}
return 0;
}