我用的是邻接表构图。
一,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