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;
const int maxn=5e6+10;
int n,m,tot,s;
int dis[maxn];
int las[maxn],nex[maxn*2],tov[maxn*2],len[maxn*2];
int d[maxn],id[maxn];
void ins(int x,int y,int z){
tov[++tot]=y,nex[tot]=las[x],las[x]=tot,len[tot]=z;
tov[++tot]=x,nex[tot]=las[y],las[y]=tot,len[tot]=z;
}
void up(int x){
while(x>1&&dis[d[x]]<dis[d[x/2]]){
swap(d[x],d[x/2]);
swap(id[d[x]],id[d[x/2]]);
x>>=1;
}
}
void down(int x){
while(x*2<=d[0]&&dis[d[x]]>dis[d[x*2]]||x*2+1<=d[0]&&dis[d[x]]>dis[d[x*2+1]]){
int k=x*2;
if(k<d[0]&&dis[d[k+1]]<dis[d[k]]) ++k;
swap(d[x],d[k]);
swap(id[d[x]],id[d[k]]);
x=k;
}
}
int main(){
scanf("%d%d%d",&n,&m,&s);
int i,j,x,y,z;
for (i=1;i<=m;++i) scanf("%d%d%d",&x,&y,&z),ins(x,y,z);
memset(dis,127,sizeof(dis));
dis[1]=0;
for (i=1;i<=n;++i) d[++d[0]]=i,id[i]=d[0],up(d[0]);
for (i=1;i<=n;++i){
int p=d[1];
d[1]=d[d[0]--];
id[d[1]]=1;
down(1);
for (j=las[p];j;j=nex[j]){
dis[tov[j]]=min(dis[tov[j]],dis[p]+len[j]);
up(id[tov[j]]);
}
}
printf("%d\n",dis[s]);
}