uva 10537 - The Toll! Revisited (逆向思维+最短路+输出字典序最小路径)

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 transported over land, passing through several towns and villages. Each town and village demanded an entry toll. There were no tolls for leaving. The toll for entering a village was simply one item. The toll for entering a town was one piece per 20 items carried. For example, to enter a town carrying 70 items, you had to pay 4items as toll. The towns and villages were situated strategically between rocks, swamps and rivers, so you could not avoid them.

 

Figure 1: To reach Samarkand with 66 spoons, traveling through a town followed by two villages, you must start with 76 spoons.

 

Figure 2: The best route to reach X with 39 spoons, starting from A, is A->b->c->X, shown with arrows in the figure on the left. The best route to reach X with 10 spoons is A->D->X, shown in the figure on the right. The figures display towns as squares and villages as circles.

 

Predicting the tolls charged in each village or town is quite simple, but finding the best route (the cheapest route) is a real challenge. The best route depends upon the number of items carried. For numbers up to 20, villages and towns charge the same. For large numbers of items, it makes sense to avoid towns and travel through more villages, as illustrated in Figure 2.

 

You must write a program to solve Sindbad’s problem. Given the number of items to be delivered to a certain town or village and a road map, your program must determine the total number of items required at the beginning of the journey that uses a cheapest route. You will also have to find the cheapest route. If there is more than one such route, print the lexicographically smallest one (A-n-d is smaller than a-n-d).


Input

The input consists of several test cases. Each test case consists of two parts: the roadmap followed by the delivery details.

 

The first line of the roadmap contains an integer n, which is the number of roads in the map (0 <= n). Each of the next n lines contains exactly two letters representing the two endpoints of a road. A capital letter represents a town; a lower case letter represents a village. Roads can be traveled in either direction.

 

Following the roadmap is a single line for the delivery details. This line consists of three things: an integer p (0 < p < 1000000000) for the number of items that must be delivered, a letter for the starting place, and a letter for the place of delivery. The roadmap is always such that the items can be delivered.

 

The last test case is followed by a line containing the number -1.

 

Output

The output consists of three lines for each test case. First line displays the case number, second line shows the number of items required at the beginning of the journey and third line shows the path according to the problem statement above. Actually, the path contains all the city/village names that Sindbad sees along his journey. Two consecutive city/village names in the path are separated by a hyphen.

 

Sample Input                             Output for Sample Input

1

a Z

19 a Z

5

A D

D X

A b

b c

c X

39 A X

-1

Case 1:

20

a-Z

Case 2:
44

A-b-c-X




题意:

有两种节点,一种是大写字母,一种是小写字母,当时小写字母是要付1各单位的过路费,当时大写字母的时候要付当前自己财务的1/20分之一当做过路费。求最少带多少个物品从起点到终点能在最后交付的时候有k个物品。


思路:

因为要输出字典序最小路径,所以必须逆向求解(这和优先关系有关系,自己画画就知道了)(衰~ 我开始也是一直二分+正向求解一直WA。。。)

逆向求解连二分都不用了,可以直接求出最小的花费,逆向求解要注意是根据该点的字母大小写来判断怎样算花费,而不是下一个点!这点坑了我好久。用path数组记录路径就能输出路径了。

WA的可以看我贴的数据,另外uva推荐使用uva board,上面的讨论真心有用。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define maxn 205
#define MAXN 100005
#define mod 100000000
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std;

ll n,m,ans,cnt,sx,ed,tot;
bool vis[maxn];
char s1[10],s2[10];
ll dist[maxn],head[maxn],path[maxn];
struct Node
{
    ll v,w,next;
} edge[MAXN];

void addedge(ll u,ll v,ll w)
{
    cnt++;
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt;
}
ll calcal(ll x)
{
    return x-ceil(x/20.0);
}
ll get(ll x)
{
    if(x%19==0) return x/19*20;
    ll t=20*x/19;
    while(calcal(t)<x) t++;
    return t;
}
void SPFA()
{
    ll i,j,nx,v;
    memset(vis,0,sizeof(vis));
    memset(path,0,sizeof(path));
    memset(dist,0x3f,sizeof(dist));
    queue<ll>q;
    path[ed]=ed;
    dist[ed]=tot;
    vis[ed]=1;
    q.push(ed);
    while(!q.empty())
    {
        nx=q.front();
        vis[nx]=0;
        q.pop();
        for(i=head[nx]; i; i=edge[i].next)
        {
            v=edge[i].v;
            if(nx>=26)
            {
                if(dist[v]>dist[nx]+1)
                {
                    dist[v]=dist[nx]+1;
                    path[v]=nx;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
                else if(dist[v]==dist[nx]+1)
                {
                    if(nx<path[v]) path[v]=nx;
                }
            }
            else
            {
                if(dist[v]>get(dist[nx]))
                {
                    dist[v]=get(dist[nx]);
                    path[v]=nx;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
                else if(dist[v]==get(dist[nx]))
                {
                    if(nx<path[v]) path[v]=nx;
                }
            }
        }
    }
}
char f(ll k)
{
    if(k>=26) return 'a'+k-26;
    return 'A'+k;
}
void output(ll k)
{
    if(k==ed) printf("%c",f(k));
    else
    {
        printf("%c-",f(k));
        output(path[k]);
    }
}
ll cal(char s[10])
{
    if(s[0]>='a') return s[0]-'a'+26;
    return s[0]-'A';
}
int main()
{
    ll i,j,u,v,w,test=0;
    while(~scanf("%lld",&n))
    {
        if(n==-1) break ;
        cnt=0;
        memset(head,0,sizeof(head));
        for(i=1; i<=n; i++)
        {
            scanf("%s%s",s1,s2);
            u=cal(s1);
            v=cal(s2);
            addedge(u,v,0);
            addedge(v,u,0);
        }
        scanf("%lld%s%s",&tot,s1,s2);
        sx=cal(s1);
        ed=cal(s2);
        SPFA();
        printf("Case %lld:\n%lld\n",++test,dist[sx]);
        output(sx);
        printf("\n");
    }
    return 0;
}
/*
0
2 A A
6
a c
c e
e d
a b
b f
f d
19 a d
25
A B
B C
C D
D E
E F
F G
G H
H I
I J
J K
K L
L M
M N
N O
O P
P Q
Q R
R S
S T
T U
U V
V W
W X
X Y
Y Z
999999999 A Z
4
A b
A B
b c
B c
18 A c
4
A b
A B
b c
B c
19 A c
5
A D
D X
A b
b c
c X
39 A X

Case 1:
2
A
Case 2:
3605038190
A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z
Case 3:
20
A-B-c
Case 4:
21
A-b-c
Case 5:
44
A-b-c-X
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值