zoukankan      html  css  js  c++  java
  • HDU 1874

    畅通工程续

    Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 88894 Accepted Submission(s): 34281

    Problem Description

    某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。

    现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。

    Input

    本题目包含多组数据,请处理到文件结束。
    每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。
    接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
    再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。

    Output

    对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1.

    Sample Input

    3 3
    0 1 1
    0 2 3
    1 2 1
    0 2
    3 1
    0 1 1
    1 2

    Sample Output

    2
    -1

    题目大意:

    多组输入,每组输入n m 表示有n个节点,m条边,之后的m行输入每个边的起点终点和权值,最后输出一行起点和终点,询问起点到终点的最短路,不能到达则输出-1。

    解题思路:

    最短路的模板题,这里介绍两种方法,以下方法均为vector存邻接表:

    • 堆优化的dijkstra算法
    • 队列优化的Bellm - Ford 算法,也就是Spfa算法

    思路一:堆优化的dijkstra算法:

    采用堆优化dijkstra算法,用优先队列维护离起点最近的点,并按照该点到起点的距离排序。每次找离起点最近的点,并以这个点的所有变进行松弛,我用了邻接表存储,将1入队,依次进行松弛,因为采用堆优化,不必考虑重边问题,每次松弛完之后入队,直到队空即可结束。AC代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <vector>
    #include <queue>
    using namespace std;
    const int mod = 1e9 + 7;
    const int N = 2e3 + 50;
    const int inf = 0x3f3f3f3f;
    typedef long long ll;
    typedef pair<int, int> pii;
    bool vis[N];
    int dis[N], n, m;
    struct pr
    {
        int to, val;
        bool operator < (const pr &t)const
        {
            return val > t.val;//按照距离升序,val小的在队首
        }
    };
    vector<pr > e[N];
    void dijkstra(int s)
    {
        priority_queue<pr > q;
        dis[s] = 0;
        q.push({s, dis[s]});
        while (!q.empty())
        {
            auto t = q.top();
            q.pop();
            if (vis[t.to])  continue;
            vis[t.to] = true;
            for (int i = 0; i < e[t.to].size(); i ++)//遍历离1最近的点的所有边并考虑是否进行松弛
            {
                int k = e[t.to][i].to;
                if (e[t.to][i].val + t.val < dis[k])
                {
                    dis[k] = e[t.to][i].val + t.val;
                    q.push({k, dis[k]});
                }
            }
        }
    }
    void init()
    {
        for (int i = 0; i <= n; i ++)//注意是0开始的,从1开始 WA了一发
        {
            vis[i] = false;
            e[i].clear();
            dis[i] = inf;
        }
    }
    int main()
    {
        while (cin >> n >> m)
        {
            init();
            for (int i = 1; i <= m; i ++)
            {
                int u, v, w;
                cin >> u >> v >> w;
                e[u].push_back({v, w});
                e[v].push_back({u, w});
            }
            int s, e;
            cin >> s >> e;
            dijkstra(s);
            if (dis[e] == inf)
              cout << -1 << endl;
            else
              cout << dis[e] << endl;
        }
        return 0;
    }
    

    思路二:SPFA算法

    将起点存入队列中,用vis数组维护该点是否在队列中,并通过该点所连的所有边进行松弛,(有点BFS的思想)如果能通过一个点松弛成功,则把该点入队,并打上标记。AC代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <vector>
    #include <queue>
    using namespace std;
    const int mod = 1e9 + 7;
    const int N = 2e3 + 50;
    const int inf = 0x3f3f3f3f;
    typedef long long ll;
    typedef pair<int, int> pii;
    bool vis[N];
    int dis[N], n, m;
    vector<pii > v[N];
    void spfa(int s)
    {
        queue<int > q;
        q.push(s);
        dis[s] = 0;
        while(!q.empty())
        {
            int now = q.front();
            q.pop(), vis[now] = false;
            for (int i = 0; i < v[now].size(); i ++)
            {
                int t = v[now][i].first;
                if (dis[now] + v[now][i].second < dis[t])
                {
                    dis[t] = dis[now] + v[now][i].second;
                    if (!vis[t])
                    {
                        vis[t] = true;
                        q.push(t);
                    }
                }
            }
        }
    }
    void init()
    {
        for (int i = 0; i <= n; i ++)
        {
            dis[i] = inf;
            vis[i] = false;
            v[i].clear();
        }
    }
    int main()
    {
        while (cin >> n >> m)
        {
            init();
            for (int i = 1; i <= m; i ++)
            {
                int a, b, val;
                cin >> a >> b >> val;
                v[a].push_back(make_pair(b, val));
                v[b].push_back(make_pair(a, val));
            }
            int s, e;
            cin >> s >> e;
            spfa(s);
            cout << (dis[e] == inf ? -1 : dis[e]) << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    用 Python 带你看各国 GDP 变迁
    Fluent Interface(流式接口)
    probing privatePath如何作用于ASP.NET MVC View
    Word插入htm文件导致文本域动态增加的一个问题
    Visual Studio 2013附加进程调试IE加载的ActiveX Control无效解决方法
    Ubuntu下Chrome运行Silverlight程序
    Windows Phone Bing lock screen doesn't change解决方法
    SPClaimsUtility.AuthenticateFormsUser的证书验证问题
    Web Service Client使用Microsoft WSE 2.0
    Visual Studio 2013安装Update 3启动crash的解决方法
  • 原文地址:https://www.cnblogs.com/Hayasaka/p/14294191.html
Copyright © 2011-2022 走看看