zoukankan      html  css  js  c++  java
  • (写给自己看)最短路系列

    (写给自己看)最短路系列

    dijkstra算法

    思想

    • 无负权的单源最短路
    • 每次扩展的是最短路径的点
    • priority_queue<node> 可轻松实现,同一节点可能有不同距离在队列中,但每次出优先队列都是最小的,也就是最短距离
    • poj1874
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include<algorithm>
    #include<queue>
    #include<stack>
    using namespace std;
    //author:fridayfang
    //date:19 2月 27
    //global varibles
    #define ll long long;
    #define inf 0x3f3f3f3f
    #define CL(a,b) memset(a,b,sizeof(a))
    #define sf(a) scanf("%d",&a)
    #define pr(a) printf("%d
    ",a)
    #define db(a) printf("db %d
    ",a)
    #define fr0(i,m) for(int i=0;i<m;i++)
    #define fr1(i,m) for(int i=1;i<=m;i++)
    const int maxn = 100 + 5;
    const int maxm = 100*100+5;
    int n,a,b,cnt;
    int head[maxn],dis[maxn];
    struct Edge{
        int v,nxt,w;
        Edge(){}
        Edge(int v_ ,int nxt_ ,int w_):v(v_),nxt(nxt_),w(w_){}
    }es[maxm];
    void add(int u,int v,int w){
        es[cnt].v=v,es[cnt].w=w;
        es[cnt].nxt=head[u],head[u]=cnt,cnt++;
    }
    struct Node{
        int idx,di;
        Node(int idx_ ,int dis_):idx(idx_),di(dis_){}
        bool friend operator < (const Node& n1,const Node& n2){
            return n1.di>n2.di;
        }
    };
    int dij(int r){
        CL(dis,0x3f);
        priority_queue<Node> q;
        dis[r]=0,q.push(Node(r,dis[r]));
        int cntn=0;
        while(!q.empty()){
            Node tmp=q.top();
            q.pop();
            int idx=tmp.idx;
            if(idx==b) return dis[idx];
            for(int t=head[idx];t!=-1;t=es[t].nxt){
                int v=es[t].v,w=es[t].w;
                if(dis[idx]+w<dis[v]){
                    dis[v]=dis[idx]+w;
                    q.push(Node(v,dis[v]));
                }
            }
        }
        return -1;   
    }
    int main(){
        sf(n),sf(a),sf(b);
        CL(head,-1);
        fr1(i,n){
            int num;sf(num);
            fr1(j,num){
                int v;sf(v);
                if(j==1) add(i,v,0);
                else add(i,v,1);
                
            }
        }
        printf("%d
    ",dij(a));
    
        
        return 0;
    }
    

    bellmanford

    思想

    • 类似动态规划,求不超过(0,1,2..(n-1))条边的最短路径
    • 每次枚举E条边(<u,v>,dis[v]<dis[u]+w[u][v]) 则更新dis[v]
    • 可判负环,(n-1)此后还能松弛则有负权环 O(E*V)
    • 优化算法 SPFA

    维护一个队列,里面存放所有需要进行迭代的点。初始时队列中只有一个
    源点S。用一个布尔数组记录每个点是否处在队列中。

    每次迭代,取出队头的点v,依次枚举从v出发的边v->u, 若
    Dist[v]+len(v->u) 小于Dist[u],则改进Dist[u](可同时将u前驱记为v)。
    此时由于S到u的最短距离变小了,有可能u可以改进其它的点,所以若u不在
    队列中,就将它放入队尾。这样一直迭代下去直到队列变空,也就是S到所
    有节点的最短距离都确定下来,结束算法。 若一个点最短路被改进的次数达
    到n ,则有负权环(原因同B-F算法) 。 可以用spfa算法判断图有无负权环

    在平均情况下, SPFA算法的期望时间复杂度为O(E)

    • p1716(这个好像是最长路,例题不太好)
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include<algorithm>
    #include<queue>
    #include<stack>
    using namespace std;
    //author:fridayfang
    //date:19 2月 27
    //global varibles
    
    #define ll long long;
    #define inf 0x3f3f3f3f
    #define CL(a,b) memset(a,b,sizeof(a))
    #define sf(a) scanf("%d",&a)
    #define pr(a) printf("%d
    ",a)
    #define db(a) printf("db %d
    ",a)
    #define fr0(i,m) for(int i=0;i<m;i++)
    #define fr1(i,m) for(int i=1;i<=m;i++)
    const int maxn = 1e4 + 5;
    const int maxm = 1e7+5;
    int cnt;
    int head[maxn],vis[maxn],dis[maxn],ct[maxn];//记录每个点进入队列次数
    struct Edge{
        int v,nxt,w;
    }es[maxm];
    void add(int u,int v,int w){
        es[cnt].v=v,es[cnt].w=w,es[cnt].nxt=head[u];
        head[u]=cnt,cnt++;
    }
    int spfa(int r,int d){//d 是目的节点
        //最长路径
        //printf("db %d %d %d
    ",r,d,n);
        CL(dis,128);//有负权,dis[]求最长路应清-inf
        //printf("db %d
    ",dis[128]);
        dis[r]=0;
        queue<int> q;q.push(r);
        vis[r]=1;//表示进入队列
        while(!q.empty()){
            int tmp=q.front();q.pop();
            vis[tmp]=0;//表示出队列
            //printf("db %d dis: %d
    ",tmp,dis[tmp]);
            for(int t=head[tmp];t!=-1;t=es[t].nxt){
                //printf("db u->v %d->%d
    ",tmp,es[t].v);
                int v=es[t].v,w=es[t].w;
                if(dis[tmp]+w>dis[v]){
                    dis[v]=dis[tmp]+w;
                    if(vis[v]) continue;
                    q.push(v);vis[v]=1;
                    //if(ct[v]>=n) return -1;//表示有环
                }
            }
    
        }
        return dis[d];
        
    }
    int main(){
        int t;sf(t);
        int minv=inf,maxv=0;
        CL(head,-1);
        int r=0;
        while(t--){
            int x,y;sf(x),sf(y);
            add(x,y+1,2);
            r=max(y,r);
        }
        r++;
        for(int i=0;i<r;i++){
            add(i,i+1,0);
            add(i+1,i,-1);
        }
        int ans=spfa(0,r);
        /*
        while(t--){
            int a,b;
            sf(a),sf(b);
            add(a,b+1,2);
            maxv=b>maxv?b:maxv;
            minv=a<minv?a:minv;
        }
        for(int i=minv;i<=maxv;i++){
            add(i,i+1,0);
            add(i+1,i,-1);
        }
        */
        //int ans=spfa(minv,maxv+1,maxv-minv+1);
        printf("%d
    ",ans);
        
        return 0;
    }
    

    floyd

    思想

    • Floyd-Warshall算法的原理是动态规划。
    • wiki即懂
    • zhihu也可
    • 也可解决传递闭包问题
    • poj2139
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include<algorithm>
    #include<queue>
    #include<stack>
    using namespace std;
    //author:fridayfang
    //date:19 2月 27
    //global varibles
    #define ll long long;
    #define inf 0x3f3f3f3f
    #define CL(a,b) memset(a,b,sizeof(a))
    #define sf(a) scanf("%d",&a)
    #define pr(a) printf("%d
    ",a)
    #define db(a) printf("db %d
    ",a)
    #define fr0(i,m) for(int i=0;i<m;i++)
    #define fr1(i,m) for(int i=1;i<=m;i++)
    const int maxn = 300 + 5;
    const int maxm = 1e6+5;
    //floyd
    int n,m;
    int path[maxn][maxn];
    int mp[maxn][maxn];
    void floyd(){
        fr1(i,n) mp[i][i]=0;
        fr1(k,n){
            fr1(i,n){
                fr1(j,n){
                    //经过1.2...k节点mp[i][j]最短路径
                    if(mp[i][k]>=inf||mp[k][j]>=inf) continue;
                    if(mp[i][j]>mp[i][k]+mp[k][j]){
                        mp[i][j]=mp[i][k]+mp[k][j];
                        path[i][j]=k;
                    }
                }
            }
        }
        /*
        fr1(i,n){
            fr1(j,n){
                printf("%d->%d: %d
    ",i,j,mp[i][j]);
            }
        }
        */
    }
    
    int cowin[maxn];
    
    int main(){
        while(~scanf("%d %d",&n,&m)){
            CL(mp,0x3f);
            while(m--){
                int t;sf(t);
                for(int j=1;j<=t;j++)sf(cowin[j]);
                fr1(i,t)
                fr1(j,t){
                    if(i!=j){
                        mp[cowin[i]][cowin[j]]=1;
                        mp[cowin[j]][cowin[i]]=1;
                    }
                }
            }
            floyd();
            int ans=inf;
            fr1(i,n){
                int tmp=0;
                fr1(j,n){
                    tmp+=mp[i][j];
                }
                ans=min(ans,tmp);
            }
            //cout<<ans*100/(n-1)<<endl;
            double avg=(ans+0.0)/(n-1.0);
            int fi=(int)(avg*100);
            
            printf("%d
    ",fi);
        }
        return 0;
    
    }
    
  • 相关阅读:
    Ext js必包含的几个文件
    设计模式之三:装饰者模式(简单实现(星巴兹咖啡))
    SQLSERVER排查CPU占用高的情况
    函数题练习52找两个数中最大者
    函数题练习53数字金字塔
    JavaScript面向对象tab栏增删改查操作
    JavaScriptObject.defineProperty方法
    Javascript面向对象迭代forEach、some、filter方法以及查询商品案例
    函数题练习51符号函数
    Javascript构造函数和原型
  • 原文地址:https://www.cnblogs.com/fridayfang/p/10519484.html
Copyright © 2011-2022 走看看