Spfa
Spfa是类似bfs的一种图论方法,运用队列更新dis[i],求得图中1~n的最短路径。
Spfa中用到dis[i]表示图中每一点距离起点的长度,bz[i]用来记录编号为i的点是否入队,a[x,y]表示图中x~y之间的距离,b[x,i]表示编号为x的点的第i条边的终点,每次更新这个终点到起点的距离,以当前入队的点来更新,最后求出答案。
tov[i]表示编号为i的边的终点;
next[i]表示编号为i的边下一个要搜索的边;
last[i]表示以i为节点开始的最后一条边;
len[i]表示编号为i的权值;
Code
#include<cstdio>
#include<cmath>;
#include<iostream>
using namespace std;
int n,m,i,next[100001],len[100001],last[10001],tov[100001],tot,head,tail,dis[10001],f[10000001];
bool bz[10001];
void insert(int x,int y,int z)
{
tot++;
len[tot]=z;
tov[tot]=y;
next[tot]=last[x];
last[x]=tot;
}
int main()
{
scanf("%d%d",&n,&m);
int x,y,z;
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
insert(x,y,z);
}
head=0;
tail=1;
for (i=1;i<=n;i++)
dis[i]=2147483647/2;
dis[1]=0;
bz[1]=true;
f[1]=1;
while (head!=tail)
{
head++;
x=f[head];
i=last[x];
while (i!=0)
{
y=tov[i];
if (dis[x]+len[i]<dis[y])
{
dis[y]=dis[x]+len[i];
if (bz[y]==false)
{
bz[y]=true;
tail++;
f[tail]=y;
}
}
i=next[i];
}
bz[x]=false;
}
for (i=2;i<=n;i++)
{
if (dis[i]!=2147483647/2)
printf("%d\n",dis[i]);
else printf("%d\n",-1);
}
}
Dijkstra
Dijkstra是一种以贪心为主导思想的单源最短路径算法。
每次找到所有dis值最小的那一个用它来更新其他点。从而实现单源最短路径。
Code
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,m,next[100001],len[100001],last[10001],tov[100001],tot,head,tail,dis[10001],f[10000001];
bool bz[10001];
void insert(int x,int y,int z)
{
len[++tot]=z;
tov[tot]=y;
next[tot]=last[x];
last[x]=tot;
}
int main()
{
scanf("%d%d",&n,&m);
int x,y,z,i,j,k,p;
memset(dis,127,sizeof(dis));
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
insert(x,y,z);
if(x==1) dis[y]=min(dis[y],z);
}
dis[1]=0;
bz[1]=true;
for (i=1;i<=n;++i)
{
p=2147483647;
for (j=1;j<=n;++j)
{
if(!bz[j]&&dis[j]<p)
{
p=dis[j];
k=j;
}
}
bz[k]=true;
for (j=last[k];j;j=next[j])
dis[tov[j]]=min(dis[k]+len[j],dis[tov[j]]);
}
for (i=2;i<=n;i++)
{
if (dis[i]<2147483647/2)
printf("%d\n",dis[i]);
else printf("%d\n",-1);
}
}
加堆优化:
Dijkstra加堆优化最大的要点就是要记录每个点在堆中的位置,并且在每次更新完之后要把那个点在堆中up一下,不然堆的形态对于更新完之后的dis值来说就是错误的。
Code
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,m,tot,head,tail,dis[10001],f[10000001];
int next[100001],len[100001],last[10001],tov[100001];
int d[100010];
bool bz[10001];
int a[100010];
void insert(int x,int y,int z)
{
len[++tot]=z;
tov[tot]=y;
next[tot]=last[x];
last[x]=tot;
}
void up(int x)
{
while(x>1&&dis[d[x]]<dis[d[x/2]])
{
swap(d[x],d[x/2]);
swap(a[d[x]],a[d[x/2]]);
x/=2;
}
}
void down(int x)
{
int k;
while(x*2<=tot&&dis[d[x]]>dis[d[x*2]]||x*2+1<=tot&&dis[d[x]]>dis[d[x*2+1]])
{
k=x*2;
if(k+1<=tot&&dis[d[k]]>dis[d[k+1]]) k++;
swap(d[x],d[k]);
swap(a[d[x]],a[d[k]]);
x=k;
}
}
int main()
{
scanf("%d%d",&n,&m);
int x,y,z,i,j,k,p;
memset(dis,127,sizeof(dis));
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
insert(x,y,z);
if(x==1) dis[y]=min(dis[y],z);
}
dis[1]=0;
bz[1]=true;
tot=0;
for (i=2;i<=n;++i)
{
d[++tot]=i;
a[i]=tot;
up(tot);
}
for (i=1;i<=n;++i)
{
k=d[1];
d[1]=d[tot],a[d[1]]=1,down(1);
for (j=last[k];j;j=next[j])
{
dis[tov[j]]=min(dis[k]+len[j],dis[tov[j]]);
up(a[tov[j]]);
}
}
for (i=2;i<=n;i++)
{
if (dis[i]<2147483647/2)
printf("%d\n",dis[i]);
else printf("%d\n",-1);
}
}