最短路的小结

一.  Dijkstra

1不适用于负权边。

2.求解“单源点”到其他顶点的最短路。(不适用于任两点最短路)

3.有无向图均适用。

4.其算法过程类似于最小生成树的prim算法,使用邻接矩阵时在输入之前应进行初始化,map[a][b]=0x3f3f3f3f;输入时输入的a,b距离要与map[a][b]比较,若map[a][b]>要输入的值方可对map[a][b]进行赋值。

5算法的描述

   for(i=1; i<=n; i++)
        {
            for(j=1; j<=n; j++)
            {
                if(i==j)
                    map[i][j]=0;
                else
                    map[i][j]=0x3f3f3f3f;
            }
        }

        int s,pos;
        memset(bj,0,sizeof(bj));
        for(i=1; i<=n; i++)
        {
            d[i]=map[1][i];
        }
        bj[1]=1;
        for(i=0; i<n-1; i++)
        {
            int mi=0x3f3f3f3f;
            for(j=1; j<=n; j++)
            {
                if(!bj[j]&&d[j]<mi )
                {
                    mi=d[j];
                    pos=j;
                }
            }
            bj[pos]=1;
            for(j=1; j<=n; j++)
            {
                if(!bj[j] &&d[j]>map[pos][j] +d[pos])
                {
                    d[j]=map[pos][j]+d[pos];
                }
            }
        }


 

 

二.  Bellman_ford

1.输入是使用结构体,输入的a,b,及权值和b,a及权值都要记录到结构体中。

2.可以计算边权为负值的最短路问题,适用于有向图和无向图

3. 在边权可正可负的图中,环有零环,正环,负环3种。若判断有负环,在进行完点数减一次找最短路后,若还能松弛,则有负权边。

 

三.  Floyd

1.输入前的初始化与Dijkstra一样,他可以求解任意两点的最短路。

2.不适用于权值为负的回路,用于无向图。

3.如果dis[i][i]!=0则证明有环。

    for(k=1; k<=n; k++)
    {
        for(i=1; i<=n; i++)
        {
            for(j=1; j<=n; j++)
            {
                if(i!=j&&(mp[i][j]>mp[i][k]+mp[k][j]   ) )
                {
                    mp[i][j]=mp[i][k]+mp[k][j];
                }
            }
        }
PS: 原理懂了,细节还要多加注意,此能用于无向图,在
if(map[a][b]>w)
{
<span style="white-space:pre">	</span>map[a][b]=w;
<span style="white-space:pre">	</span>map[b][a]=w;//因为没有加这一条错了几次!
}




 四.SPFA

1.求单源最短路,且无负环。

2.过程:

先初始化,各点距离为无穷,再将源点放入队列中,然后拿出与其相连接的点进行松弛,如果松弛成功并且队列里没有此点,将此点放入队列,并标记。直到遍历所有与当前点相连的点后,把当前点去掉标记。不断重复上面操作,直到队列中没有元素为止。

1)临接表的的实现

#include<iostream>//注意只有SPFA才有vis标记数组。
#include<queue>
#include<cstring>
using namespace std;
int n,m,z;
struct node
{
    int a,w,next;//a,为各点,w为权值,next指向与当前点相连的下一个点。
}q[100010];
int head[100010],dis[100010],vis[100010];
void spfa(int s,int e)
{
    int i,j,k;
    queue<int >qu;
    for(i=1;i<=n;i++)
        dis[i]=0x3f3f3f3f;
    dis[s]=0;
    qu.push(s);
    while(!qu.empty())
    {
        k=qu.front();//用刚出队的点作为源点刷新与他相连点的距离。
        qu.pop();
        for(i=head[k];i!=-1;i=q[i].next)
        {
            int a=q[i].a;
            if(dis[a]>dis[ k ]+q[i].w)//如何才能刷新与其他店的距离
            {
                dis[a]=dis[k]+q[i].w;肯定是源点到其他点的距离大于源点+权值,故才能被更新
                if(!vis[a])
                {
                    qu.push(a);//进队,标记
                    vis[a]=1;
                }
            }
        }
        vis[k]=0;
    }
    if(dis[  n   ]==0x3f3f3f3f)
        cout<<"-1"<<endl;
    else
        cout<<dis[n]<<endl;
}
int main()
{
    int i,j,k;
    while(cin>>n>>m&&n&&m)
    {
        z=0;
        int a,b,c;
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        for(i=0;i<m;i++)
        {
            cin>>a>>b>>c;
            q[z].a=a;
            q[z].w=c;
            q[z].next=head[b];//a的下一个点指向b;
            head[b]=z++;
            q[z].a=b;
            q[z].w=c;
            q[z].next=head[a];
            head[a]=z++;
        }
        spfa(1,n);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值