UVA 10537 TollRevisited

从终点逆推,d[u]表示进入u以后剩下的货物,那么进入u之前的货物数量设为y,d[u] = x,那么y-x=ceil(y/20.0)=(y-1)/20+1=(y+19)/20。

(y-x)*20+r=y+19,0≤r≤19,即19*y=20*x+r,根据题意y应该尽量小,x的部分是不能变动的,所以y=x+ceil(x/19.0)。

然后从起点找一条字典序最小的路径即可,因为每个字母都是独一无二的,所以不必bfs,每次记录一个点就够了。

因为isalphaWA了7发,次奥啊

#include<bits/stdc++.h>
using namespace std;

const int maxn = 54, maxm = maxn*maxn, town = 0, village = 1;
bool g[maxn][maxn];
int head[maxn],nxt[maxm],to[maxm],ecnt;
int tp[maxn];
int id[256];
char rid[256];

void addEdge(int u,int v)
{
    to[ecnt] = v;
    nxt[ecnt] = head[u];
    head[u] = ecnt++;
}
int id_cnt;

void init()
{
    memset(head,-1,sizeof(head));
    memset(id,-1,sizeof(id));
    memset(g,0,sizeof(g));
    ecnt = 0;
    id_cnt = 0;
}

inline int ID(char c) {
    if(~id[c]) return id[c];
    id[c]= id_cnt;
    rid[id_cnt] = c;
    tp[id_cnt] = ‘a‘<=c&&c<=‘z‘;//写成isalpha(c)-1;WA了
    return id_cnt++;
}
typedef long long ll;
typedef pair<ll,int> Node;
#define fi first
#define se second

ll d[maxn];
void dijkstra(int s,ll p)
{
    memset(d,0x7f,sizeof(d));
    priority_queue<Node,vector<Node>,greater<Node> > q;
    q.push(Node(d[s] = p,s));
    while(q.size()){
        Node x = q.top(); q.pop();
        int u = x.se;
        if(d[u] != x.fi) continue;
        ll t = (tp[u]?(1+d[u]):((d[u]+18)/19+d[u]));
        for(int i = head[u]; ~i; i = nxt[i]){
            int v = to[i];
            if(d[v] > t ){
                q.push(Node(d[v]= t,v));
            }
        }
    }
}

ll cost(int u,int v)
{
    return tp[v]?1:((d[u]+19)/20);
}

void FindPath(int s,int e)
{
    int u = s;
    while(u != e){
        printf("%c-",rid[u]);
        int nex = -1;
        for(int i = head[u]; ~i; i = nxt[i]){
            int v = to[i];
            if(d[u]- cost(u,v) >= d[v]){
                if(~nex) {
                    if(rid[v] < rid[nex]) nex = v;
                }else nex = v;
            }
        }
        swap(nex,u);
    }
    printf("%c\n",rid[e]);
}

int main()
{
    //freopen("in.txt","r",stdin);
    int n;
    char a[10],b[10];
    int kas = 0;
    while(scanf("%d",&n),~n){
        init();
        while(n--){
            scanf("%s%s",a,b);
            int u = ID(*a), v = ID(*b);
            if(!g[u][v]){
                g[u][v] = g[v][u] = true;
                addEdge(u,v); addEdge(v,u);
            }
        }
        ll p;
        scanf("%lld%s%s",&p,a,b);
        int s = ID(*a),e = ID(*b);
        dijkstra(e,p);
        printf("Case %d:\n%lld\n",++kas,d[s]);
        FindPath(s,e);
    }
    return 0;
}
时间: 2024-11-07 17:22:49

UVA 10537 TollRevisited的相关文章

UVA 10537 - The Toll! Revisited(dijstra扩展)

UVA 10537 - The Toll! Revisited 题目链接 题意:给定一个无向图,大写字母是城市,小写字母是村庄,经过城市交过路费为当前货物的%5,路过村庄固定交1,给定起点终点和到目标地点要剩下的货物,问最少要带多少货物上路,并输出路径,如果有多种方案,要求字典序最小 思路:dijstra的逆向运用,d数组含义变成到该结点至少需要这么多货物,然后反向建图,从终点向起点反向做一遍 这题被坑了..并不是输出的城市才存在,比如下面这组样例 0 1 A A 应该输出 1 A 代码: #i

uva 10537 Toll! Revisited(优先队列优化dijstra及变形)

Toll! Revisited 大致题意:有两种节点,一种是大写字母,一种是小写字母.首先输入m条边,当经过小写字母时需要付一单位的过路费,当经过大写字母时,要付当前财务的1/20做过路费.问在起点最少需要带多少物品使到达终点时还有k个物品.当有多条符合条件的路径时输出字典序最小的一个. 思路:已知终点的权值,那么可以从终点向前推.求终点到起点的最短路径,然后按字典序打印路径. 比较难处理的是:向前推时前驱节点的权值计算.列个方程算算就可以了,主要时不能整除的情况. 计算前驱结点dis值的时候,

UVA - 10537 The Toll! Revisited (最短路变形逆推)

Description Problem G Toll! Revisited Input: Standard Input Output: Standard Output Time Limit: 1 Second Sindbad the Sailor sold 66 silver spoons to the Sultan of Samarkand. The selling was quite easy; but delivering was complicated. The items were t

UVA 10537最小树(逆向+字典序输出)

The Toll! Revisited Sindbad the Sailor sold 66 silver spoons to the Sultan of Samarkand. The selling was quite easy; but delivering was complicated. The items were transported over land, passing through several towns and villages. Each town and villa

UVA 10537 The Toll! Revisited 过路费(最短路,经典变形)

题意:给一个无向图,要从起点s运送一批货物到达终点e,每个点代表城镇/乡村,经过城镇需要留下(num+19)/20的货物,而经过乡村只需要1货物即可.现在如果要让p货物到达e,那么从起点出发最少要准备多少货物?输出答案和路径(多条路径则必须输出字典序最小的).注:终点需要花费,而起点不需要. 思路:这最短路变形的不错.要逆推过来求最短路径,那么就从e出发到s的距离!只是p比较大,而且城镇还得推出前一站到底需要多少货物,既然直接计算那么麻烦,也可以一直p++直到能留下p为止就推出来了:而乡村就容易

UVA 562 Dividing coins --01背包的变形

01背包的变形. 先算出硬币面值的总和,然后此题变成求背包容量为V=sum/2时,能装的最多的硬币,然后将剩余的面值和它相减取一个绝对值就是最小的差值. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 50007 int c[102],d

UVA 10341 Solve It

Problem F Solve It Input: standard input Output: standard output Time Limit: 1 second Memory Limit: 32 MB Solve the equation: p*e-x + q*sin(x) + r*cos(x) + s*tan(x) + t*x2 + u = 0 where 0 <= x <= 1. Input Input consists of multiple test cases and te

UVA 11014 - Make a Crystal(容斥原理)

UVA 11014 - Make a Crystal 题目链接 题意:给定一个NxNxN的正方体,求出最多能选几个整数点.使得随意两点PQ不会使PQO共线. 思路:利用容斥原理,设f(k)为点(x, y, z)三点都为k的倍数的点的个数(要扣掉一个原点O).那么全部点就是f(1),之后要去除掉共线的,就是扣掉f(2), f(3), f(5)..f(n).n为素数.由于这些素数中包括了合数的情况,而且这些点必定与f(1)除去这些点以外的点共线,所以扣掉.可是扣掉后会扣掉一些反复的.比方f(6)在f

[UVa] Palindromes(401)

UVA - 401 Palindromes Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description A regular palindrome is a string of numbers or letters that is the same forward as backward. For example, the string "ABCDED