zoukankan      html  css  js  c++  java
  • NC 追债之旅 (dijkstra+分层图)

    题意:给一张n个节点,m条双向边的图,每条边具有花费,每一天走一条边,每一天也具有花费。
    问小明从1号结点到n号结点k天之内能否到达,能到达输出最小花费,否则输出-1。
    解法:一开始没有想到建分层图,直接dijkstra贪心走最小花费,但是会出现一个问题,就是
    到达一个结点的最小花费,会被其他路径天数并不匹配的路径所利用,从而得到答案错误。
    hack数据:
    4 4 2
    1 2 1
    1 3 1000
    2 3 5
    3 4 4999
    0 1
    如果没建分层图,1-2-3的最短花费先被更新为7,1-3-4这条路径中3-4这一次更新会利用1-2-3的最小花费更新到4的路径,导致答案错误。
    所以为了避免这种天数不匹配的情况,需要分层建图,或则dis数组多开一维记录信息。dis[i][j]表示到达i结点路径长为j的最小花费
    这样转移就不会出现天数不匹配的情况。

    #include <bits/stdc++.h>
    typedef long long ll ;
    //#define int ll
    int quickpow(int a , int b , int mo){int ans = 1 ;while(b){ if(b&1){ans = ans * a % mo ;}b >>= 1 ;a = a * a % mo ;}return ans ;}
    using namespace std ;
    #define INF 0x3f3f3f3f
    const double PI = acos(-1.0);
    const int maxn = 1e4+9;
    const int mod = 1e9+7;
    int n , m , k ;
    int dis[maxn][20];
    bool vis[maxn][20];
    int da[maxn];
    vector<pair<int , int>>g[maxn];
    struct node{
        int u , w , t ;
        bool operator < (const node e) const{
            return w > e.w;
        }
        node(int _u , int _w , int _t){
            u = _u , w = _w , t = _t ;
        }
    };
    
    void dijkstra(int u){
        priority_queue<node>q;
        for(int i = 1 ; i <= n ; i++){
            for(int j = 0 ; j <= k ; j++){
                dis[i][j] = INF;
                vis[i][j] = false;
            }
        }
        dis[u][0] = 0 ;
        q.push(node{u , dis[u][0] , 0});
        while(!q.empty()){
            node now = q.top() ; q.pop();
            int u = now.u , nt = now.t;
            vis[u][nt] = 1;
            if(nt >= k) continue;
            for(auto j : g[u]){
                int v = j.first , w = j.second , t = nt + 1;
                if(!vis[v][t] && dis[v][t] > dis[u][nt] + w + da[t]){
                    dis[v][t] = dis[u][nt] + w + da[t];
                    q.push(node{v , dis[v][t] , t});
                }
            }
        }
    }
      
    void Solve(){
        cin >> n >> m >> k ;
        for(int i = 1 ; i <= m ; i++){
            int u , v , w ;
            cin >> u >> v >> w ;
            g[u].push_back({v , w});
            g[v].push_back({u , w});
        }
        for(int i = 1 ; i <= k ; i++){
            cin >> da[i];
        }
        dijkstra(1);
        int ans = INF;
        for(int i = 1 ; i <= k ; i++){
            ans = min(ans , dis[n][i]);
        }
        cout << (ans == INF ? -1 : ans) << endl;
    }
      
      
    signed main(){
        #ifdef ONLINE_JUDGE
        #else
            freopen("D:\c++\in.txt", "r", stdin);
        #endif
            Solve();
    }
    
  • 相关阅读:
    20162329张旭升 2017-2018-2 《程序设计与数据结构》第一周学习总结
    20162329 张旭升2016-2017《程序设计与数据结构》课程总结
    实验报告五
    20162329 张旭升 阶段四则运算(挑战出题)
    实验四:Android 开发基础
    四则运算的整体总结(第二周)
    结对编程四则运算(阶段总结)
    团队项目-选题报告
    第二次结对编程作业
    第一次结对编程作业
  • 原文地址:https://www.cnblogs.com/nonames/p/13455219.html
Copyright © 2011-2022 走看看