• POJ 3635 Full Tank(最短路径变形 + 优先队列)


    题意:

    给 n 个城市 m 条路,每个城市有个加油站,但是收费单价不同,现给你几个查询并给定汽车的装油量, 问你从 S 城市到 T 城市的最小费用。

    思路:

    1. 如果是一条路径上面的加油站问题,比较容易解决,有动规方程:dp[i][j] 即到 i 站还剩下 j 升油的费用;

    2. 现在涉及到图中的类似问题,并且数据规模还挺大的,直接针对每条边都进行一次转移,会 TLE,因为中间产生了很多无用的状态;

    3. 因为要求最小费用,如果到达 T 时恰好油量为 0,则此时肯定是最优解的条件之一了。所以这个时候我们借鉴 dijstra 中最短路径的思路,

       每次只加 1 升油,等价于把每个加油站又分解为 C + 1 个点,利用贪心的策略,每次寻找最小的费用即可.

    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    const int MAXN = 1010;
    const int MAXM = 110;
    const int INFS = 0x3fffffff;
    
    struct ST {
        int u, fuel, cost;
        ST(int _u, int _fuel, int _cost) : u(_u), fuel(_fuel), cost(_cost) {}
        bool operator < (const ST& other) const { return cost > other.cost; }
    };
    
    struct edge {
        int v, d;
        edge* next;
    } *V[MAXN], ES[MAXN*10*2];
    
    int EC, price[MAXN], dp[MAXN][MAXM];
    bool vis[MAXN][MAXM];
    
    void addedge(int u, int v, int d) {
        ES[++EC].next = V[u];
        V[u] = ES + EC;
        V[u]->v = v; V[u]->d = d;
    }
    
    int bfs(int s, int t, int vol) {
        priority_queue<ST> Q;
        Q.push(ST(s, 0, 0));
        dp[s][0] = 0;
    
        while (!Q.empty()) {
            int u = Q.top().u;
            int fuel = Q.top().fuel;
            int cost = Q.top().cost;
            Q.pop();
    
            vis[u][fuel] = true;
    
            if (u == t)
                return cost;
    
            if (fuel + 1 <= vol && !vis[u][fuel+1] &&
                dp[u][fuel+1] > dp[u][fuel] + price[u]) {
                    dp[u][fuel+1] = dp[u][fuel] + price[u];
                    Q.push(ST(u, fuel+1, dp[u][fuel+1]));
            }
    
            for (edge* e = V[u]; e; e = e->next) {
                int v = e->v;
                int f = fuel - e->d;
                if (f >= 0 && !vis[v][f] && dp[v][f] > cost) {
                    dp[v][f] = cost;
                    Q.push(ST(v, f, cost));
                }
            }
        }
        return -1;
    }
    
    int main() {
        int n, m;
        while (~scanf("%d%d", &n, &m)) {
            for (int i = 0; i < n; i++)
                scanf("%d", &price[i]);
    
            EC = 0;
            memset(V, 0, sizeof(V));
            for (int i = 0; i < m; i++) {
                int u, v, d;
                scanf("%d%d%d", &u, &v, &d);
                addedge(u, v, d);
                addedge(v, u, d);
            }
            int cases;
            scanf("%d", &cases);
            while (cases--) {
                int vol, s, t;
                scanf("%d%d%d", &vol, &s, &t);
    
                for (int i = 0; i <= n; i++)
                    for (int j = 0; j <= vol; j++)
                        dp[i][j] = INFS, vis[i][j] = false;
    
                int ans = bfs(s, t, vol);
                if (ans != -1)
                    printf("%d\n", ans);
                else
                    printf("impossible\n");
            }
        }
    
        return 0;
    }
  • 相关阅读:
    C#事件(event)解析
    dll加入到GAC后,如何方便的调试
    『C程序设计』读书笔记系列文章之第四章 逻辑运算和判断选取控制
    C#委托之个人理解
    虚方法(virtual)和抽象方法(abstract)的区别
    『C程序设计』读书笔记系列文章之第二章 数据类型、运算符与表达式
    SOA概览(转)
    今天学的几个有用的句型
    【老孙随笔】PPT高手的启示
    【项目经理之修炼(11)】《初级篇》什么样的项目经理才可能成功??
  • 原文地址:https://www.cnblogs.com/kedebug/p/2995244.html
Copyright © 2020-2023  润新知