• 图论-Dijkstra算法


    //使用邻接矩阵并记录路径的Dijkstra
    #include<vector> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int MAXV = 1000; const int INF = 0xFFFFFFF; int n,m,G[MAXV][MAXV]; int d[MAXV]; int pre[MAXV]; bool vis[MAXV]={false}; void Dijkstra(int s) { for(int i=0;i<n;i++) d[i]=INF,pre[i]=i; //fill(d,d+MAXV,INF); d[s]=0; for(int i=0;i<n;i++)//必须把每个定点标记为访问过 { int u=-1,MIN=INF; for(int j=0;j<n;j++) { if(vis[j]==false && d[j]<MIN) { u=j; MIN=d[j]; } } if(u==-1) return ; //说明无法到达其他的定点,也就是其他的点到s的距离为d[i]=INF,此时直接返回即可 vis[u]=true; //访问这一点 for(int v=0;v<n;v++) { if(vis[v]==false && G[u][v]!=0 && d[u]+G[u][v]<d[v]) { d[v]=d[u]+G[u][v]; pre[v]=u; } } } } void print(int u) { if(pre[u]!=u) print(pre[u]); printf("%d ",u); } int main(void) { int s,u,v,w; cin>>n>>m>>s; for(int i=0;i<m;i++) { cin >> u >> v >> w; G[u][v]=w; } Dijkstra(s); for(int i=0;i<n;i++) printf("%d ",d[i]); printf(" "); for(int i=0;i<n;i++) { print(i); printf(" "); } return 0; }

    测试数据:

    6 8 0
     0 1 1 
     0 3 4 
     0 4 4 
     1 3 2 
     2 5 1 
     3 2 2 
     3 4 3 
     4 5 3
    第一行是n,m,s;
    然后是m行起点,终点,权重
    //使用邻接表的Dijkstra,输出路径
    #include<cstdio> #include<iostream> #include<vector> #include<algorithm> using namespace std; const int MAXV = 1000; const int INF = 0xFFFFFFF; int n,pre[MAXV],d[MAXV],vis[MAXV]; struct Node{ int v,dis; Node(int _v,int _dis){ v=_v; dis=_dis; } }; vector<Node>Adj[MAXV]; void print(int u) { if(pre[u]!=u) print(pre[u]); printf("%d ",u); } void Dijkstra(int s) { for(int i=0;i<n;i++) d[i]=INF,pre[i]=i; d[s]=0; for(int i=0;i<n;i++) { int u=-1,MIN=INF; for(int j=0;j<n;j++) { if(vis[j]==false && d[j]<MIN) { u=j; MIN=d[j]; } } if(u==-1) return ; vis[u]=true; for(int j=0;j<Adj[u].size();j++) { int v=Adj[u][j].v; if(vis[v]==false && d[u]+Adj[u][j].dis<d[v]) { pre[v]=u; d[v]=d[u]+Adj[u][j].dis; } } } } int main(void) { int u,v,w,m,s; cin>>n>>m>>s; for(int i=0;i<m;i++) { cin >> u >> v >> w; Adj[u].push_back(Node(v,w)); } Dijkstra(s); for(int i=0;i<n;i++) printf("%d ",d[i]); printf(" "); for(int i=0;i<n;i++) { printf("路径:%d:",i+1); print(i); printf(" "); } return 0; }

     输出路径的函数使用如下更加方便:

    void DFS(int s,int v)
    {
        if(v==s)
        {
            printf("%d
    ",v);
            return ;    
        }    
        DFS(S,pre[v]);
        printf("%d
    ",v);
    } 

     Dijkstra算法在有两条或者两条以上的最短路径可以到达同一个地方的时候,一般会给出第二个标尺。

    1.边的权值

    2.点的权值

    3.最短的路径的个数

    //边权的使用,邻接矩阵的情况,注意初始化只有c[v]=0,其他为INF
    //对于邻接表,可以使用邻接表存放一个顶点可以到达的其他点,然后将边权仍然放到一个矩阵中,方便查询
    for
    (int v=0;v<n;v++) { if(vis[v]==false && G[u][v]!=INF) { if(d[u]+G[u][v]<d[v]) { d[v]=d[u]+G[u][v]; c[v]=c[u]+cost[u][v]; } else if(d[u]+G[u][v]==d[v] && c[u]+cost[u][v]<c[v]) { c[v]=c[u]+cost[u][v]; } } }
    //增加点权的情况,初始化时候只有w[s]=weight[s],其他为INF
    for
    (int v=0;v<n;v++) { if(vis[v]==false && G[u][v]!=INF) { if(d[u]+G[u][v]<d[v]) { d[v]=d[u]+G[u][v]; w[v]=w[u]+weight[v]; } else if(d[u]+G[u][v]==d[v] && w[v]<w[u]+weight[v]) { w[v]=w[u]+weight[v] } } }
    //计算路径:初始化只有num[s]=1,其他为INF;
    for
    (int v=0;v<n;v++) { if(vis[v]==false && G[u][v]!=INF) { if(d[u]+G[u][v]<d[v]) { d[v]=d[u]+G[u][v]; num[v]=num[u]; } else if(d[u]+G[u][v]==d[v]) { num[v]+=num[u]; } } }

    举例子:

    给出N个城市,M条无向边。每个城市都有一定的救援小组,所有边的权值已知(此处的边权不是路径长度,是第二尺度)。给出起点和终点,求从起点到终点的最短路径条数以及路径上的救援小组之和。如果有多条最短路径,输出救援小组数目之和最大的。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int MAXV = 1000;
    const int INF = 0xFFFFFFF;
    //n为定点数,m为边数,st起点,ed终点
    //G为邻接矩阵,weight为点权
    //d[]记录最短路径长度,w[]记录最大点权之和,num[]记录最短路径数量
    int n,m,st,ed,G[MAXV][MAXV],weight[MAXV];
    int d[MAXV],w[MAXV],num[MAXV];
    bool vis[MAXV]={false};
    void Dijkstra(int s)
    {
        fill(d,d+MAXV,INF);
        memset(num,0,sizeof(num));    
        memset(w,0,sizeof(w));
        d[s]=0;
        w[s]=weight[s];
        num[s]=1;
        for(int i=0;i<n;i++)
        {
            int u=-1,MIN=INF;
            for(int j=0;j<n;j++)
            {
                if(vis[j]==false && d[j]<MIN)
                {
                    u=j;
                    MIN=d[j];
                }
            }
            if(u==-1) return ;
            vis[u]=true;
            for(int v=0;v<n;v++)
            {
                if(vis[v]==false && G[u][v]!=INF)
                {
                    if(d[u]+G[u][v]<d[v])
                    {
                        d[v]=d[u]+G[u][v];
                        w[v]=w[u]+weight[v];
                        num[v]=num[u];    
                    }    
                    else if(d[u]+G[u][v]==d[v])
                    {
                        if(w[u]+weight[v]>w[v]) w[v]=w[u]+weight[v];
                        num[v]+=num[u]; //写在if的外面 
                    }
                }    
            } 
        }
    }
    int main(void)
    {
        scanf("%d%d%d%d",&n,&m,&st,&ed);
        for(int i=0;i<n;i++) scanf("%d",&weight[i]);
        int u,v;
        fill(G[0],G[0]+MAXV*MAXV,INF);
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&u,&v);
            scanf("%d",&G[u][v]);
            G[v][u]=G[u][v];    
        }    
        Dijkstra(st);
        //for(int i=0;i<n;i++) printf("%d  %d  %d
    ",d[i],w[i],num[i]); 
        printf("%d %d
    ",num[ed],w[ed]);
        return 0;
    } 
    /*
    5 6 0 2
    1 2 1 5 3
    0 1 1
    0 2 2
    0 3 1
    1 2 1
    2 4 1
    3 4 1
    答案:2 4  
    */

     Dijkstra+DFS

    //Dijkstra部分
    void
    Dijkstra(int s) { fill(d,d+MAXV,INF); d[s]=0; for(int i=0;i<n;i++)//必须把每个定点标记为访问过 { int u=-1,MIN=INF; for(int j=0;j<n;j++) { if(vis[j]==false && d[j]<MIN) { u=j; MIN=d[j]; } } if(u==-1) return ; //说明无法到达其他的定点,也就是其他的点到s的距离为d[i]=INF,此时直接返回即可 vis[u]=true; //访问这一点 for(int v=0;v<n;v++) { if(vis[v]==false && G[u][v]!=INF) { if(d[u]+G[u][v]<d[v]) { d[v]=d[u]+G[u][v]; pre[v].clear(); pre[v].push_back(u); } else if(d[u]+G[u][v]==d[v]) { pre[v].push_bakc(u); } } } } }
    //DFS部分
    int
    optvalue; vector<int>pre[MAXV]; vector<int>path,tempPath; void DFS(int v) { if(v==st) { tempPath.push_back(v); int value; 计算路径tempPath上的value的值:累加边权或者点权的和 if(value 优于 optvalue) { optvalue=value; path=tempPath; } tempPath.pop_back(); } tempPath.push_back(v); for(int i=0;i<pre[v].size();i++) { DFS(pre[u][i]); } tempPath.pop_back(v); }

    总结:裸的迪杰斯特拉使用邻接表计算,带有第二尺度的使用Dijkstra的邻接矩阵的方法计算,复杂的第二尺度,使用Dijkstra+DFS计算。

  • 相关阅读:
    一文读懂Lua元表
    React-Antd Pro环境搭建
    如何在QT项目中引入Boost库
    .NET Core RSA PKCS8 格式 签名/验签
    Chrome控制台Network请求过滤
    字符串拼接null值问题
    复制文件夹需要考虑的问题
    [闻缺陷则喜]关于boost的想法
    公共库开发组
    docker-compose 一键部署分布式配置中心Apollo
  • 原文地址:https://www.cnblogs.com/zuimeiyujianni/p/8836706.html
Copyright © 2020-2023  润新知