• 图的最短路径Dijkstra


    #include <stdio.h>
    #include <string.h> 
    #include <vector>
    #include <queue>
    #include <iostream> 
    using namespace std;
    
    const int MAXV = 1000;
    const int INF = 1000000000; 
    
    struct Node
    {
        int v,dis;    
    };
    
    vector<Node> Adj[MAXV];
    
    int n;//n为顶点数,图G使用邻接表实现,MAXV为最大顶点数(点数决定如何遍历边)
    int m;// 边数(决定输入什么样的图) 
    int s;//起点
     
    int d[MAXV];//起点到达各个点的最短路径长度
    bool vis[MAXV] = {false};//标记数组,vis[i]==true表示已访问,初值均为false
    
    int pre[MAXV]={0}; //记录到某一个点的前驱 
    
    void Dijkstra(int s)
    {
        fill(d,d+MAXV,INF);
        d[s] = 0;//起点s到达自身的距离为0
        
        //遍历所有的点 
        for(int i=0;i<n;i++)
        {
            //u为使得d[u]最小的点,MIN存放该最小的d[u] 
            int u = -1,MIN = INF;
            //每一趟找一个已连通的最短路径的点出来 
            for(int j=0;j<n;j++)
            {
                
                if(vis[j] == false && d[j] < MIN)
                {
                    u = j;
                    MIN = d[j];
                }
             } 
             
             //找不到小于INF的d[u],说明剩下的顶点和起点s不连通 
             if(u == -1)
             {
                 return;
             }
             //找到了 
             else
             {
                 vis[u] = true;//找到则标记成已访问,每一趟可以确定一个最短点
                 
                 //遍历u能到达的所有顶点v,并判断以u为中转到j的距离是否比原来的小,如果小则更新 
                for(int j=0;j < Adj[u].size();j++)
                {
                    
                    int v = Adj[u][j].v;
                    
                    //以当前最短路径的点为中转,看看是否比原来的距离小 ,如果小,则优化d[v] 
                    if(vis[v] == false && d[u] + Adj[u][j].dis < d[v])
                    {
                        d[v] = d[u] + Adj[u][j].dis;
                        
                        //记录前驱
                        pre[v] = u; 
                     } 
                 } 
             } 
         } 
     } 
     
     //输出从起点到v的最短路径 
     void print(int s,int v)
     {
         if(v == s)
         {
             cout << s << endl;
             return;
         }
         
         print(s,pre[v]);
         cout<< v << endl;
     } 
    
    int main()
    {
        //顶点个数,边数,起点编号 
        cin >> n >> m >> s;
        
        int u,v,w;
        Node tmp;
        for (int i=0;i<m;i++)
        {
            cin >> u >> v >> w;
            tmp.v = v;
            tmp.dis = w;
            Adj[u].push_back(tmp);
        }
        
        Dijkstra(s);
        
        for(int i=0;i<n;i++)
        {
            cout << d[i] << " ";
        }
    
        cout << endl;
        print(0,5);
        return 0;
        
    }

    练习: PAT A1003 Emergency 

    #include <vector>
    #include <string>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    const int MAXV = 510;
    const int INF = 1000000000;
    
    //n为点数,m为边数,st和ed分别为起点和终点
    //G为邻接矩阵,weight为点权 
    //d[]记录最短距离,w[]记录最大点权之和
    int n,m,st,ed,G[MAXV][MAXV],weight[MAXV]; 
    int d[MAXV],w[MAXV];
    //vis[i] == true 表示顶点i已访问 
    bool vis[MAXV] = {false}; 
    
    vector<int> pre[MAXV];
    
    void Dijkstra(int s)
    {
        fill(d,d+MAXV,INF);
        d[s] = 0;
        
        //每次找出一个最短的点,一共找n个 ,最短的点就是在最短路径中的点,设置为访问 
        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;
            
            //看u能到哪些点 ,并以u为中转,更新其他距离 
            //以u为中转,到v 
            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();
                        //令v的前驱为u 
                        pre[v].push_back(u); 
                    }
                    else if(d[u]+G[u][v] == d[v])
                    {
                        pre[v].push_back(u);
                     } 
                 } 
            } 
        }
    }
    
    //求最大值
    int optvalue = -INF; 
    //最优路径及临时路径 
    vector<int> path,tempPath;
    //路径数+1 
    int totalCount = 0;
    
    void DFS(int v)
    {
        
        //    cout << endl;
        //到达叶子节点,即起点 
        if(v == st)
        {
            totalCount++;
            tempPath.push_back(v);
            int value = 0;
            for(int i=0;i<tempPath.size();i++)
            {
    //            value = value + G[ tempPath[i] ][ tempPath[i+1] ];
                value = value + weight[tempPath[i]];
             } 
             
             if(value > optvalue)
             {
                 optvalue = value;
                 path = tempPath;
             }
             
             //回溯
             tempPath.pop_back();
             return; 
        } 
        //将当期访问的点加入临时路径 
        tempPath.push_back(v);
        //访问所有前驱 
        for(int i=0;i<pre[v].size();i++)
        {
            //递归遍历所有前驱 
            DFS(pre[v][i]);
        }
        tempPath.pop_back(); 
     } 
    
    int main()
    {
        cin >> n >> m >> st >> ed;
        for(int i=0;i<n;i++)
        {
            cin >> weight[i];
        }
        
        int u,v;
        fill(G[0],G[0] + MAXV * MAXV,INF);
        
        for(int i=0;i<m;i++)
        {
            cin >> u >> v;
            cin >> G[u][v];
            G[v][u] = G[u][v];
         } 
        
        Dijkstra(st);
        
        
        DFS(ed);
        
        cout << totalCount << " " << optvalue << endl;
        return 0;
    }

     PAT A1030 Travel Plan

    #include <iostream>
    #include <stdio.h>
    #include <string>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    const int MAXV = 510;
    const int INF = 1000000000;
    
    //n为顶点数,m为边数,st和ed分别为起点和终点 
    //G为距离矩阵,cost为花费矩阵
    //d[]用来记录最短距离,minCost记录最短路径上的最小花费 
    int n,m,st,ed,G[MAXV][MAXV],cost[MAXV][MAXV];
    int d[MAXV],minCost = INF;
    //是否被访问过 
    bool vis[MAXV] = {false};
    //前驱 
    vector<int> pre[MAXV];
    vector<int> tempPath,path;//临时路径与最优路径 
    
    void Dijkstra(int s)
    {
        fill(d,d+MAXV,INF);
        d[s] = 0;
        //找出n个点 
        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;
             
             //更新d[] 
             for(int v = 0;v < n;v++)
             {
                 //如果能到达则做为中转 ,看能否到达v,并判断以此为中转到v的距离是否比之前的d要小,如果小则更新 
                 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_back(u);
                    }
                } 
             }
         } 
    }
    
    //v为当前节点 
    void DFS(int v)
    {
        //到达叶节点 
        if(v == st) 
        {
            tempPath.push_back(v);
            int tempCost = 0;//记录当前路径的花费之和
            for(int i = tempPath.size() - 1;i > 0;i--)
            {
                int id = tempPath[i],idNext = tempPath[i-1];
                tempCost += cost[id][idNext];
            }
            
            //如果小,则备份 
            if(tempCost < minCost)
            {
                minCost = tempCost;
                path = tempPath;
             } 
             
             //回溯
             tempPath.pop_back() ;
             return;
        }
        
        tempPath.push_back(v);
        for(int i=0;i<pre[v].size();i++)
        {
            DFS(pre[v][i]);
        }
        
        tempPath.pop_back();
    } 
    
    int main()
    {
        
        cin >> n >> m >> st >> ed;
        int u,v;
        fill(G[0],G[0]+MAXV*MAXV,INF) ;
        
        for(int i=0;i<m;i++)
        {
            cin >> u >> v;
            cin >> G[u][v];
            cin >> cost[u][v];
            G[v][u] = G[u][v];
            cost[v][u] = cost[u][v];
        }
        
        Dijkstra(st);
        
        DFS(ed);//获取最优路径
        
        for(int i=path.size() - 1;i>=0;i--)
        {
            cout << path[i] << " ";
         } 
         cout << d[ed] << " " << minCost << endl;
        return 0;
    }
  • 相关阅读:
    test
    c# cook book -Linq 关于Object的比较
    关于UnitOfWork
    autofac学习
    webapi 开启跨域支持
    httpclient通过post提交到webapi
    jQuery之元素查找
    jQuery之过滤元素
    jQuery之回到顶部
    jQuery之_元素滚动
  • 原文地址:https://www.cnblogs.com/xiaochi/p/10409972.html
Copyright © 2020-2023  润新知