先从最简单的入手!图用邻接矩阵保存,算法为Dijkstra单源最短路径算法。
#define N 1000
#define Inf 9999999
int edge[N][N],dist[N],n,vis[N];
void dij(int s)
{
int i,j,k;
for(i = 1; i <= n; i++)
dist[i] = edge[s][i];
memset(vis,0,sizeof(vis));
vis[s] = true;
for(j = 1; j <= n-2; j++)
{
k = 1;
while(vis[k])k++;
int beg=k;
for(i = k + 1; i <= n; i++)
if(!vis[i] && dist[i] < dist[k])
k = i;
vis[k] = true;
for(i = beg + 1; i <= n; i++)
if(!vis[i] && dist[k] + edge[k][i] < dist[i])
dist[i] = dist[k] + edge[k][i];
}
}
图用静态邻接表表示,算法仍为Dijkstra单源最短路径算法。静态邻接表相比于动态邻接表的优点在于它在程序的开始一次性分配大块的内存,使得添加边的时候不必再动态申请内存。
#define N 10000
#define Inf 9999999
struct Edge
{
int to,w,next;
}e[100000];
int ec,pp[N],n,dist[N];
bool vis[N];
void dij(int s)
{
int i,j,k;
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
dist[i]=Inf;
dist[s]=0;
for(j=1;j<=n-1;j++)
{
k=1;
while(vis[k])k++;
for(i=k+1;i<=n;i++)
if(!vis[i]&&dist[i]<dist[k])
k=i;
vis[k]=true;
for(i=pp[k];i!=-1;i=e[i].next)
if(!vis[e[i].to]&&dist[k]+e[i].w<dist[e[i].to])
dist[e[i].to]=dist[k]+e[i].w;
}
}
下面是一种用优先队列优化的Dijkstra单源最短路径算法。
#define Inf 9999999
#define N 1000
struct Edge
{
int to,w,next;
}e[100000];
int ec,pp[N],n,dist[N];
bool vis[N];
struct Node
{
int u,d;
bool operator<(const struct Node a)const
{
return d>a.d;
}
}t1;
void dijkstra(int s)
{
int i,j,k;
priority_queue<struct Node>que;
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
dist[i]=Inf;
dist[s]=0;
t1.u=s;t1.d=0;
que.push(t1);
while(!que.empty())
{
t1=que.top();
que.pop();
k=t1.u;
if(vis[k])continue;
vis[k]=true;
for(i=pp[k];i!=-1;i=e[i].next)
if(!vis[e[i].to]&&dist[k]+e[i].w<dist[e[i].to])
{
dist[e[i].to]=dist[k]+e[i].w;
t1.u=e[i].to;
t1.d=dist[e[i].to];
que.push(t1);
}
}
}
下面是一种最简单的求最短路径的算法(floyd),当然它的复杂度也最高。
#define N 1000
int f[N][N],n;
void floyd()
{
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(f[i][k]+f[k][j]<f[i][j])
f[i][j]=f[i][k]+f[k][j];
}
Dijkstra算法在图存在负权回路的情况下则会失效,下面的Bellman-ford算法则能用于存在负权回路的图。
#define Inf 9999999
#define N 1000
int edge[N][N],dist[N],n;
bool bellman(int s)//存在负权回路返回ture,不存在则返回false
{
int i,j,k;
for(i=1;i<=n;i++)
dist[i]=Inf;
dist[s]=0;
for(k=1;k<=n-1;k++)
{
bool flag=true;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(dist[i]+edge[i][j]<dist[j])
{
flag=false;
dist[j]=dist[i]+edge[i][j];
}
}
}
if(flag)
return false;
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(dist[i]+edge[i][j]<dist[j])
return true;
return false;
}
下面是bellman-ford算法用于以静态邻接表保存的图的情况。
#define N 1000
#define Inf 9999999
struct Edge
{
int u,v,w;
}e[10000];
int n,dist[N],cnt;
bool bellman(int s)//存在负权回路返回true,否则返回false
{
int i,j,k;
for(i=1;i<=n;i++)
dist[i]=Inf;
dist[s]=0;
for(j=1;j<=n-1;j++)
{
bool flag=true;
for(i=0;i<cnt;i++)
{
if(dist[e[i].u]+e[i].w<dist[e[i].v])
{
flag=false;
dist[e[i].v]=dist[e[i].u]+e[i].w;
}
}
if(flag)
return false;
}
for(i=0;i<cnt;i++)
if(dist[e[i].u]+e[i].w<dist[e[i].v])
return true;
return false;
}
相比于SPFA最短路径算法,上面的最短路算法简直都弱爆了,SPFA算法不仅能用于存在负权回路的情况,而且复杂度也是所有最短路算法中最低的。
#define N 1000
#define Inf 9999999
int edge[N][N],n,dist[N],que[N];
bool inque[N];
void spfa(int s)
{
int i,j,k,head=0,tail=0;
for(i=1;i<=n;i++)
dist[i]=Inf;
dist[s]=0;
memset(inque,0,sizeof(inque));
que[tail++]=s;
inque[s]=true;
while(head<tail)
{
k=que[head++];
inque[k]=false;
for(i=1;i<=n;i++)
if(dist[k]+edge[k][i]<dist[i])
{
dist[i]=dist[k]+edge[k][i];
if(!inque[i])
{
que[tail++]=i;
inque[i]=true;
}
}
}
}
下面是SPFA用于以静态邻接表保存的图的情况。
#define N 1000
#define Inf 9999999
struct Edge
{
int to,w,next;
}e[1000000];
int ec,pp[N],n,dist[N],que[N*N];
bool inque[N];
void spfa(int s)
{
int i,j,k,head=0,tail=0;
for(i=1;i<=n;i++)
dist[i]=Inf;
memset(inque,0,sizeof(inque));
dist[s]=0;
que[tail++]=s;
inque[s]=true;
while(head<tail)
{
k=que[head++];
inque[k]=false;
for(i=pp[k];i!=-1;i=e[i].next)
if(dist[k]+e[i].w<dist[e[i].to])
{
dist[e[i].to]=dist[k]+e[i].w;
if(!inque[e[i].to])
{
que[tail++]=e[i].to;
inque[e[i].to]=true;
}
}
}
}
上面两种SPFA算法都是用队列来实现的,下面的这种则用栈来实现。
#define Inf 9999999
#define N 1000
struct Edge
{
int to,w,next;
}e[100000];
int pp[N],ec,n,sta[N],dist[N];
bool insta[N];
void spfa(int s)
{
int i,j,k,top=0;
memset(insta,0,sizeof(insta));
for(i=1;i<=n;i++)
dist[i]=Inf;
dist[s]=0;
sta[++top]=s;
insta[s]=true;
while(top!=0)
{
k=sta[top--];
insta[k]=false;
for(i=pp[k];i!=-1;i=e[i].next)
if(dist[k]+e[i].w<dist[e[i].to])
{
dist[e[i].to]=dist[k]+e[i].w;
if(!insta[e[i].to])
{
sta[++top]=e[i].to;
insta[e[i].to]=true;
}
}
}
}