我用的是鄰接表構圖。
一,dijstar的優先隊列優化(附打印路勁)
const int N=1100;
int head[N],cnt;
int d[N],pre[N];
struct node
{
int u,d;
bool operator<(const node x)const
{
return x.d<d;
}
};
struct maps
{
int v,w,next;
}edge[N*N];
void init()
{
cnt=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)
{
edge[cnt].v=v,edge[cnt].w=w;
edge[cnt].next=head[u],head[u]=cnt++;
}
void dijstar(int s)
{
//memset(pre,-1,sizeof(pre));
memset(d,0x3f,sizeof(d));
priority_queue<node> q;
node cur,next;
cur.u=s,cur.d=0;
d[s]=0;
q.push(cur);
int i,u,v,w;
while(!q.empty())
{
cur=q.top();
q.pop();
u=cur.u;
if(d[u]!=cur.d) continue;
for(i=head[u];i!=-1;i=edge[i].next)
{
<span style="white-space:pre"> </span> v=edge[i].v,w=edge[i].w;
if(d[v]>d[u]+w)
{
d[v]=d[u]+w;
pre[v]=u;
next.u=v,next.d=d[v];
q.push(next);
}
}
}
}
void prpath(int s,int t)
{
int js=0,tmp[N];
while(t!=s)
{
tmp[++js]=t;
t=pre[t];
}
for(int i=js;i>=1;i--)
printf("%d->",tmp[i]);
printf("%d\n",s);
}
二,Bellman-Ford。
int Bellman_Ford(int s)
{
for(int i = 1; i <= n; ++i) //初始化
d[i] = (i == s ? 0 : MAX);
for(int i = 1; i < n ; ++i)
for(int j = 1; j <= m; ++j)
if(d[e[j].v] > d[e[j].u] + e[j].w) //鬆弛(順序一定不能反~)
{
d[e[j].v] = d[e[j].u] + e[j].w
pre[e[j].v] = e[j].u;
}
int flag = 1; //判斷是否含有負權迴路
for(int i = 1; i <= m; ++i)
if(d[e[i].v] > d[e[i].u] + e[i].w)
{
flag = 0;
break;
}
return flag;
}
三,spfa(基於Bellman-Ford)
SPFA算法有兩個優化算法
SLF 和 LLL: SLF:Small Label First 策略,設要加入的節點是j,隊首元素爲i,若dist(j)<dist(i),則將j插入隊首,否則插入隊尾。 LLL:Large Label Last 策略,設隊首元素爲i,隊列中所有dist值的平均值爲x,若dist(i)>x則將i插入到隊尾,查找下一元素,直到找到某一i使得dist(i)<=x,則將i出對進行鬆弛操作。 SLF 可使速度提高 15 ~ 20%;SLF + LLL 可提高約 50%。 在實際的應用中SPFA的算法時間效率不是很穩定,爲了避免最壞情況的出現,通常使用效率更加穩定的Dijkstra算法。
const int N=110;
const int M=N*N;
int d[N],p[N],cnt[N],q[M];
int head[N],js;//,pre[N];
struct node
{
int v,w,next;
}e[M];
void add(int u,int v,int w)
{
e[js].v=v,e[js].w=w;
e[js].next=head[u],head[u]=js++;
}
void init()
{
//memset(pre,-1,sizeof(pre));
memset(head,-1,sizeof(head));
js=0;
}
int spfa(int s,int n)
{
memset(d,0x3f,sizeof(d));
memset(p,0,sizeof(p));
memset(cnt,0,sizeof(cnt));
int u,v,w,l=0,r=0;
q[++r]=s,d[s]=0,p[s]=1;
while(l<r)
{
p[u=q[++l]]=0;
for(int i=head[u];i!=-1;i=e[i].next)
{
v=e[i].v,w=e[i].w;
if(d[v]>d[u]+w)
{
d[v]=d[u]+w;
//pre[v]=u;
if(!p[v])
{
if(++cnt[v]>n) //存在負環
return 0;
p[v]=1;
q[++r]=v;
}
}
}
}
return 1;
}
void prpath(int s,int t)
{
int js=0,tmp[N];
while(t!=s)
{
tmp[++js]=t;
t=pre[t];
}
for(int i=js;i>=1;i--)
printf("%d->",tmp[i]);
printf("%d\n",s);
}
三,全源最短路Floyd
注意: d[i][i]實際上表示「從頂點
i 繞一圈再回來的最短路徑」,因此圖存在負環當且僅當 d[i][i]<0。
int d[N][N],path[N[N],n;//path記錄路徑,d表示初始距離(若相連則初始化爲邊權,若無則爲無窮大)
int floyd()
{
int i,j,k;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
path[i][j]=j;
for(k=1;k<=n;k++)
{
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(d[i][k]+d[k][j]<d[i][j])
{
d[i][j]=d[i][k]+d[k][j];
path[i][j]=path[i][k];
if(i==j&&d[i][j]<0) ////存在負環
return 0;
}
}
}
}
return 1;
}
void prpath(int u,int v)
{
printf("%d->%d: \n",u,v);
printf("%d",u);
while(u!=v)
{
printf("->%d",path[u][v]);
u=path[u][v];
}
printf("\n");
}
參考文章:http://www.renfei.org/blog/weighted-shortest-path.html
http://www.haodaima.net/art/2233075