zoukankan      html  css  js  c++  java
  • 最短路刷题感想以及模板

    感想:

    感想?不敢想不敢想。

    刷了一整个最短路专题,其中大部分都是kuangbin带我飞系列的题

    期间写了无数个神奇的bug

    也曾经通宵调bug(摸鱼)过,暑训的快感来源于此

    为了避免之后再踩同样的坑、总结出了一点点模板

    还有自己对最短路里面各个算法的一点点体会

    1.floyd

    目测是最简单的最短路算法吧

    3个for 的复杂度爆炸的算法

    不过用来写一些数据量特别小的题还是特别舒服的

    代码如下:

    const int maxn = 1005;
    int dis[maxn][maxn];
    
    void floyd(){
        for(int k=0;k<n;k++){
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    if(dis[i][j]>dis[i][k]+dis[k][j]){
                        dis[i][j]=dis[i][k]+dis[k][j];
                    }
                }
            }
        }
    }
    /*
    floyd的邻接矩阵的用法
    n表示顶点个数
    dis[i][j]表示从点i到点j的权值大小
    复杂度为O(n^3),emmm数据在100、200之间的题可以用
    作为最短路入门了
    */
    View Code

    2.dijkstra

    这个就稍微有难度了

    一开始都是对着板子写题,其实刷题刷多了,这个算法的套路也了解了

    复杂度是E*O(V)的 边乘以点

    经过优先队列的优化后甚至可以达到nlog(n)的级别

    思想也很简单,像最小生成树的kruskal的算法一样,我们都是从起始点出发

    找距离最短/最长的边,加入队列,一个个进行比较的

    最后可以打出来一个dis的表(emmm大佬别打我,我理解的dis是一个表,如果有错,麻烦指出

    这个dis的表的意义就是从起点到各个点的最短/最长的距离的集合

    于是我们就可以得到单源每一个点到各个点的最短路

    所以dijkstra适合用于单源最短路的情况

    但是不适合有负权环的情况 

    代码如下:

    const int maxn =  1005;
    int mp[maxn][maxn]
    bool vis[maxn];
    int  dis[maxn];
    int dijkstra(int st,int ed){
        vis[st]=1;
        for(int i=1;i<=n;i++){
            dis[i]=mp[1][i];
        }
        int x,minn;
        for(int i=1;i<=n;i++){
            minn=INF;
            for(int j=1;j<=n;j++){
                if(!vis[j]&&minn>dis[j]){
                    minn=dis[j];
                    x=j;
                }
                vis[x]=1;
                for(int j=1;j<=n;j++)}{
                    if(dis[j]>dis[x]+mp[x][j]){
                        dis[j]=dis[k]+mp[x][j];
                    }
                }
        }
        return dis[ed];
    }
    /*
    dijsktra的邻接矩阵的用法,
    n表示顶点个数
    其中mp是邻接矩阵的存图,
    vis是是否走过的标记
    dis是从起点出发到点i距离的最小/最大值
    mp、dis初始化为INF
    注意题目如果有重边的话需要处理一下
    */
    View Code
    const int maxn = 1005;
    typedef pair<double,int>P;
    int dis[maxn];
    bool vis[maxn];
    void dijkstra(int st){
        memset(dis,INF,sizeof(dis));
        memset(vis,0,sizeof(vis));
        priority_queue(P,vector<P>,greater<P> ) q;
        d[st]=0;
        q.push(P(0,st));
        while(!q.empty()){
            int x=p.top().second;
            q.pop();
            if(vis[x]) continue;
            vis[x] = 1;
            for(int i = 1; i <= n; i++) {
                if(dis[i] > dis[x] + mp[x][i]) {
                    dis[i] = dis[x] + mp[x][i];
                    q.push(make_pair(dis[i], i));
                }
            }
        }
    }
    View Code

    3.spfa

    spfa和bfs算法很像、把可以走的点丢进队列里面,然后每一个都走到不能走为止

    然后就可以得到最短路了

    因为是从起点到后面所有的点,可以适用于多源最短路的处理情况

    我暂时实现了普通的队列版本、手动模拟队列的版本、堆栈的版本待更新

    (听说手写堆会特别快

    我建图习惯前向星建图(不容易被POJ卡

    代码如下:

    const int maxn = 1e5+5;
    struct node{
        int to,next,w;
    }edge[maxn];
    int head[maxn];
    bool vis[maxn];
    int t=0;
    void add(int u,int v,int w){
        edge[t].to=v;
        edge[t].w=w;
        edge[t].next=head[u];
        head[u]=t++;
    }
    void spfa(int st){
    //spfa还可以用堆栈、模拟队列来写,貌似会快一些
        memset(vis,0,sizeof(vis));
        memset(dis,INF,sizeof(dis));
        queue<int> q;
        q.push(st);
        vis[st]=1;
        dis[st]=0;
        while(!q.empty()){
            int u=q.front();
            q.pop();
            vis[u]=0;
            for(int i=head[u];i!=-1;i=edge[i].next){
                int v=edge[i].to;
                if(dis[v]>dis[u]+edge[i].w){
                    dis[v]=dis[u]+edge[i].w;
                }
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    /*
    spfa算法
    其中n代表顶点个数
    dis[i]代表从起点出发到达i点的最短/最长(依据实际情况而定)距离
    vis[i]代表i这个点是否走过
    用邻接表的前向星写法有助于存储边多点少的图
    用head表示上一个节点
    输入之前记得将head初始化为-1
    */
    View Code
    const int maxn = 1e5+5;
    struct node{
        int to,next,w;
    }edge[maxn];
    int head[maxn];
    int q[maxn];  //用数组来模拟队列貌似会快一点点
    bool vis[maxn];
    int t=0;
    void add(int u,int v,int w){
        edge[t].to=v;
        edge[t].w=w;
        edge[t].next=head[u];
        head[u]=t++;
    }
    void spfa(int st){
        memset(vis,0,sizeof(vis));
        memset(dis,INF,sizeof(dis));
        queue<int> q;
        q.push(st);
        vis[st]=1;
        dis[st]=0;
        q[0]=st;
        int top=1;
        while(top!=0){
            top--;
            int u=q[top];
            vis[u]=0;
            for(int i=head[u];i!=-1;i=edge[i].next){
                int v=edge[i].to;
                if(dis[v]>dis[u]+edge[i].w){
                    dis[v]=dis[u]+edge[i].w;
                }
                if(!vis[v]){
                    vis[v]=1;
                    q[top++]=v;
                }
            }
        }
    }
    /*
    spfa算法用模拟队列实现
    其实就只是用数组模拟队列
    稍微改了一点点,随缘减少常数吧应该还是
    嘤嘤嘤
    */
    View Code

    最短路最重要的还是建图

    要有读题后把题目抽象成图形的能力

    所以需要多刷题  遇见各种各样类型的题目才好

    学习kuangbin大神的

    人一我十,人十我万!

    不停的奋斗吧,给凌晨的自己一碗鸡汤

    每一个不曾刷题的日子 都是对生命的辜负 从弱小到强大,需要一段时间的沉淀,就是现在了 ~buerdepepeqi
  • 相关阅读:
    JavaScript对象的几种创建方式?
    TCP 三次握手,四次挥手
    常用的状态码
    前后端分离的接口规范
    京东架构师:日均 5 亿查询量的ElasticSearch架构如何设计?
    [转] 谈谈Spring中都用到了那些设计模式?
    [转]Post和Get的区别
    [转]17个常用的JVM参数
    从入门到熟悉HTTPS的9个问题
    布式事务和解决方案理论
  • 原文地址:https://www.cnblogs.com/buerdepepeqi/p/9393712.html
Copyright © 2011-2022 走看看