zoukankan      html  css  js  c++  java
  • Uva 10537 过路费

    题目链接:http://vjudge.net/contest/143062#problem/C

    题意:

    给定一个无向图,大写字母是城市,小写字母是村庄,经过城市交过路费为当前货物的%5,路过村庄固定交1,给定起点终点和到目标地点要剩下的货物,问最少要带多少货物上路,并输出路径,如果有多种方案,要求字典序最小.

    分析:

    逆向最短路: 因为要求的就是起点的货量,从终点出发求最短路,但是,费用的计算要处理,重新定义d 数组,d[i] 表示,进入节点 I 以后,还要多少 d[i] 个 货品 才能到达终点。d[T] = P;

    然后就是怎么求 d[i] 了,根据 i 的类型, i >=26 ,就需要 d[i] + 1; 

    否则就是 20 里面抽 1;

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 52 + 10;
    const long long INF = 1LL << 60;
    
    int n;
    int G[maxn][maxn];
    bool mark[maxn];
    int p;
    int src;
    int dest;
    long long d[maxn];
    
    int read_node()
    {
        char ch[9];
        scanf("%s", ch);
        if(ch[0] >= 'A' && ch[0] <= 'Z') return ch[0] - 'A';
        else return ch[0] - 'a' + 26;
    }
    
    char format_node(int u)
    {
        return u < 26 ? 'A' + u : 'a' + (u - 26);
    }
    
    // 拿着item个东西去结点next,还剩多少个东西
    long long forward(long long item, int next)
    {
        if(next < 26) return item - (item + 19) / 20;
        return item - 1;
    }
    
    // 至少要拿着多少个东西到达结点u,交税以后还能剩d[u]个东西
    long long back(int u)
    {
        if(u >= 26) return d[u]+1;
        long long X = d[u] * 20 / 19; // 初始值
        while(forward(X, u) < d[u]) X++; // 调整
        return X;
    }
    
    void solve()
    {
        n = 52; // 总是有52个结点
        memset(mark, 0, sizeof(mark));
        d[dest] = p;
        mark[dest] = 1;
        for(int i = 0; i < n; i++) if(i != dest)
            {
                d[i] = INF;
                if(G[i][dest]) d[i] = back(dest);
            }
    
        // Dijkstra主过程,逆推
        while(!mark[src])
        {
            // 找最小的d
            int minu = -1;
            for(int i = 0; i < n; i++) if(!mark[i])
                {
                    if(minu < 0 || d[i] < d[minu]) minu = i;
                }
            mark[minu] = 1;
            // 更新其他结点的d
            for(int i = 0; i < n; i++) if(!mark[i])
                {
                    if(G[i][minu]) d[i] = min(d[i], back(minu));
                }
        }
    
        printf("%lld
    ", d[src]);
        printf("%c", format_node(src));
        int u = src;
        long long item = d[src];
        while(u != dest)
        {
            int next;
            for(next = 0; next < n; next++) // 找到第一个可以走的结点
                if(G[u][next] && forward(item, next) >= d[next]) break;
            item = d[next];
            printf("-%c", format_node(next));
            u = next;
        }
        printf("
    ");
    }
    
    int main()
    {
        int kase = 0;
        while(scanf("%d", &n) == 1 && n >= 0)
        {
            memset(G, 0, sizeof(G));
            for(int i = 0; i < n; i++)
            {
                int u = read_node();
                int v = read_node();
                if(u != v) G[u][v] = G[v][u] = 1;
            }
            scanf("%d", &p);
            src = read_node();
            dest = read_node();
            printf("Case %d:
    ", ++kase);
            solve();
        }
        return 0;
    }
  • 相关阅读:
    此刻,很想那些老朋友
    985工程介绍
    211工程介绍
    蓝牙耳机声音断断续续
    不支持用淋浴洗澡
    在HY买饭
    成长路上的六个W
    屎、洗脚水
    Ubuntu更换软件源
    视频流媒体服务器RTMP和RTSP区别是什么?如何区分?
  • 原文地址:https://www.cnblogs.com/TreeDream/p/6105265.html
Copyright © 2011-2022 走看看