最短路径算法

    先从最简单的入手!图用邻接矩阵保存,算法为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;
                }
            }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值