最短路

左心房为你撑大大i 提交于 2020-01-19 15:24:42

  最短路是图论的基础部分。其中学过4个主要算法,分别是Floyed,Dijkstra,Ford,SPFA。SPFA作为Ford的队列实现,有一定的优化,因此就不说Ford了。

  首先两点间距离读取都是一样的。

memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;++i) f[i][i]=0;
for(int i=1;i<=e;++i)
{
    scanf("%d%d%d",&a,&b,&distance);
    f[a][b]=distance;
    f[b][a]=distance;
}

   Floyed。特点是解决了所有点的最短路,且试用于负边权的情况。但时间复杂度是O(n^3),所以一般用处不大。

#define FOR(i,x,y) for(int i=x;i<=y;++i)
#define MIN(a,b) a<b?a:b
FOR(k,1,n) FOR(i,1,n) FOR(j,1,n) f[i][j]=MIN(f[i][j],f[i][k]+f[k][j]);

   Dijkstra。特点是计算了单点间最短路,不能在负边权的时候使用。时间复杂度O(n^2),可以考虑使用。

int Dijkstra(int st,int en)
{
    memset(vis,0,sizeof(vis));
    FOR(i,1,n) ans[i]=f[st][i];
    FOR(i,1,n)
    {
        minn=0x3f3f3f3f; k=-1;
        FOR(j,1,n) if(!vis[j]&&ans[j]<minn)
        {
            minn=ans[j];
            k=j;
        }
        if(k==-1) break;
        vis[k]=true;
        FOR(j,1,n) ans[j]=MIN(ans[j],ans[k]+f[k][j]);
    }
    return ans[en];
}

   SPFA。特点是计算单点间最短路,可以计算负边权最短路,不能直接算负边权回路。时间复杂度O(E),优先推荐使用。(有时候会被卡掉,所以Dijkstra也要会)

  hdu1874是模板题。

   写这个我还学了一下邻接表。。以前都是用邻接矩阵写的,太耗内存了。

#include <cstdio>
#include <cstring>
#define MS(a,b) memset(a,b,sizeof(a))
#define FOR(i,x,y) for(int i=x;i<=y;++i)
const int o=210,maxx=1010;
int ans,st,en,n,m,a,b,c,k,top,rear,itr,head[maxx],dis[o],point[o];
bool vis[o];
struct EDGE
{
    int v,w,next;
}edge[maxx];
void addedge(int s,int v,int w)
{
    edge[itr].v=v;
    edge[itr].w=w;
    edge[itr].next=head[s];
    head[s]=itr++;
}
int spfa(int st,int en)
{
    FOR(i,1,n) dis[i]=0x3f3f3f3f;//表示与起点的距离
    dis[st]=0; top=1; rear=0; point[1]=st; vis[st]=true;//队列准备
    while(top!=rear)
    {
        rear=(rear+1)%o;//循环队列
        k=point[rear];//取出这个点
        vis[k]=false;//该地点已访问
        for(int i=head[k];i!=-1;i=edge[i].next) if(dis[edge[i].v]>dis[k]+edge[i].w)//最短路
        {
            dis[edge[i].v]=dis[k]+edge[i].w;
            if(!vis[edge[i].v])//入队
            {
                top=(top+1)%o;
                point[top]=edge[i].v;
                vis[edge[i].v]=true;
            }
        }
    }
    return dis[en];
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        MS(edge,0); MS(head,-1); MS(point,0); MS(vis,0);//分别为邻接表,head数组,队列,访问判断
        itr=0;
        FOR(i,1,m)
        {
            scanf("%d%d%d",&a,&b,&c);
            addedge(a+1,b+1,c);//加1是为了让编号从1到N...
            addedge(b+1,a+1,c);
        }
        scanf("%d%d",&st,&en);
        ans=spfa(st+1,en+1);
        if(ans<0x3f3f3f3f)printf("%d\n",ans);
        else printf("-1\n");
    }
    return 0;
}

  

  

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!