zoukankan      html  css  js  c++  java
  • 最短路问题

      1何为最短路

      最短路算是OI上的经典问题了,最简单的问题为:在一个图上,求一个点到其他点的最短距离,即单源最短路。较为复杂的有求所有点到除它以外的其他点的最短路,即多源最短路。最短路的算法有很多,如dijkstra,floyd,bellman-ford,SPFA等,由于一些原因,除了判负环以外,SPFA基本会被卡住,因此在本文就不赘述了,本文主要讲dijkstra和floyd。

      2.1dijkstra原理概述

      dijkstra是对一个无负权边求单源最短路的算法,它是基于一个贪心的算法:设点A是距离原点O最近的未考虑的点,那么,设点B是另外一个未考虑的点,那么由于O点到B点的距离大于O点到A点的距离,所以即使点A到点B的距离为0,也是直接走O->A比O->B->A短。因此,我们求出A,再用A改变其他点即可。

      2.2代码实现

      首先看这道题:【模板】单源最短路径(弱化版)

      这道题中,我们注意到n的值较小,可以用n2 的时间复杂度的算法求解,由于m的大小,我们用链式前向星记录

    #include <bits/stdc++.h>
    using namespace std;
    int k,i,j,ne[500001],to[500001],he[500001],l[500001],cnt,min1,n,m,s,d[100001],x,y,z;
    bool b[100001];
    int main()
    {
      cnt=0;
      cin>>n>>m>>s;
      for (i=1; i<=n; i++)
      {
        b[i]=true;
        d[i]=2147483647;//初始化,d数组记录点i到点s的距离,b数组记录该点是否被访问过
      }
      for (i=1; i<=m; i++)
      {
        cin>>x>>y>>z;
        cnt++;
        ne[cnt]=he[x];
        to[cnt]=y;
        l[cnt]=z;
        he[x]=cnt;//链式前向星储存边
      }
      d[s]=0;
      d[0]=2147483647;
      for (i=2; i<=n; i++)//因为最后一点无需改变,所以只需n-1遍
      {
        min1=0;
        for (j=1; j<=n; j++)
          if (b[j]&&(d[j]<=d[min1])) min1=j;//求出最近点
        k=he[min1];
        b[min1]=false;
        while (k!=0)
        {
          d[to[k]]=min(d[to[k]],d[min1]+l[k]);//修改其他点
          k=ne[k];
        }
      }
      for (i=1; i<=n; i++)
        cout<<d[i]<<' ';
      return 0;
    }

      这样,这道题就做完了。

      接下来,我们看这道题:【模板】单源最短路径(标准版)

      在这道题中,n到了十万,显然,n2的时间复杂度太大了,考虑一下该算法的优化,我们原本用for来求最近距离,如果用堆的话,不就到nlogn了吗?这道题就能做出来了:

    #include<bits/stdc++.h>
    using namespace std;
    priority_queue<pair<long long,long long> >q;//虽然是大根堆,但是第一维取负后就是小根堆了
    long long n,m,s,i,cnt,x,y,z,he[100001],ne[200001],l[200001],to[200001],d[100001];
    bool b[100001];
    int main()
    {
        scanf("%lld%lld%lld",&n,&m,&s);
        for (i=1;i<=m;i++)
        {
            scanf("%lld%lld%lld",&x,&y,&z);
            cnt++;
            ne[cnt]=he[x];
            to[cnt]=y;
            l[cnt]=z;
            he[x]=cnt;
        }
        memset(d,100000007,sizeof(d));
        d[s]=0;
        q.push(make_pair(0,s));//压入s
        while (q.size())
        {
            x=q.top().second;//取出最近点
            q.pop();
            if (b[x]) continue;
            b[x]=true;//记录已找
            for (i=he[x];i!=0 ;i=ne[i])
                if (d[to[i]]>d[x]+l[i])
                {
                    d[to[i]]=d[x]+l[i];
                    q.push(make_pair(-d[to[i]],to[i]));//压入堆
                }
        }
        for (i=1;i<=n;i++)
        printf("%lld ",d[i]);
        return 0;
    }

      这样,dijkstra就告一段落了,若读者想要做增强的应用题,我找出以下几道题:

      小鸟的点心,该题题解

      路径统计,该题题解

      密室,该题题解

      抓住czx,该题题解

      (博主推销自己题解,哈哈,该博客只用来写洛谷题题解,欢迎参观

      3.1floyd原理概述

      floyd是一种求多源最短路的算法,设i,j是我们要求的两点,而k是两点中的一点且与i,j联通,那么i->j的距离就是min(i->j,i->k->j)枚举i,j,k,时间复杂度为n3

      3.2代码实现

      由于一下没找到例题,博主自己弄了一道:【模板】floyd

      这是一道裸的floyd模板题,先看核心代码:

        for (k=1;k<=n;k++)//k必须在最外面
            for (i=1;i<=n;i++)
                for (j=1;j<=n;j++)//i,j随便
                p[i][j]=min(p[i][j],p[i][k]+p[k][j]);//p[i][j]代表i到j的最短距离

      由于时间复杂度较大,floyd主要求多源的问题,而且也基本无法优化了,不多说了,这是完整代码:

    #include<bits/stdc++.h>
    using namespace std;
    long long n,m,p[501][501],i,j,k,ans,x,y,l;
    int main()
    {
        scanf("%lld%lld",&n,&m);
        for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)
            p[i][j]=1e17;//初始化
        for (i=1;i<=m;i++)
        {
            scanf("%lld%lld%lld",&x,&y,&l);
            p[x][y]=min(p[x][y],l);//可能有重边,取最小值
            p[y][x]=p[x][y];
        }
        for (k=1;k<=n;k++)
            for (i=1;i<=n;i++)
                for (j=1;j<=n;j++)
                p[i][j]=min(p[i][j],p[i][k]+p[k][j]);
        for (i=1;i<=n;i++)
        {
            ans=0;
            for (j=1;j<=n;j++)
                if (j!=i) 
                    ans=(ans+p[i][j])%998244354;//嘿嘿,不是998244353哦
            printf("%lld
    ",ans);
        }
        return 0;
     } 

      本章就结束了,谢谢!

  • 相关阅读:
    Arr
    class4
    class3联大网页
    class33
    class3
    人机交换 NO 1书签
    大数据的框架与特点
    mapreduce排序
    mapreduce求平均数
    mapreduce去重
  • 原文地址:https://www.cnblogs.com/szbszb/p/11280672.html
Copyright © 2011-2022 走看看