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 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 atown was one piece per
20 items carried. For example, to enter a town carrying70 items, you had to pay4 items 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 with76 spoons.


Figure 2: The best route to reach X with 39 spoons, starting fromA, is
A->b->c->X, shown with arrows in the figure on the left. The best route to reachX 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 to20, 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 Figure2.

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 thana-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 integerp (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/20个单位,给你起点和终点,让你求找一条缴纳过路费最少的路线,多条的话要字典序

思路:逆着推最短路,坑的是边界处理,不再是20而是19,没注意,W到死啊,在找字典序的话,ASCII越小就越小

#include<cstdio>
#include<cmath>
#include<ctype.h>
#include<vector>
#include<cstring>
using namespace std;
const int maxn = 55;
typedef long long ll;
const ll INF = 1ll<<62;

vector<int> G[maxn];
bool vis[maxn];
ll dis[maxn];

void dijkstra(int s, int e, ll x, int n) {
	for (int i = 1; i <= n; i++)
		dis[i] = INF;
	dis[s] = x;
	memset(vis, 0, sizeof(vis));
	for (int i = 0; i < n; i++) {
		int index;
		ll Min = INF;
		for (int j = 1; j <= n; j++)
			if (!vis[j] && dis[j] < Min) {
				Min = dis[j];
				index = j;
			}
		if (Min == INF)
			break;
		vis[index] = 1;
		for (int j = 0; j < G[index].size(); j++) {
			ll tmp;
			if (index < 27)
				tmp = (ll) ceil(dis[index]/19.0);
			else tmp = 1;
			if (dis[index]+tmp < dis[G[index][j]] && !vis[G[index][j]])
				dis[G[index][j]] = dis[index]+tmp;
		}
	}
}

int main() {
	int n;
	int u, v;
	int cas = 1;
	ll x;
	char s[10], e[10];
	while (scanf("%d", &n) != EOF && n != -1) {
		for (int i = 1; i <= 52; i++)
			G[i].clear();
		for (int i = 0; i < n; i++) {
			scanf("%s%s", s, e);
			if (isupper(s[0]))
				u = s[0] - 'A' + 1;
			else u = s[0] - 'a' + 27;
			if (isupper(e[0]))
				v = e[0] - 'A' + 1;
			else v = e[0] - 'a' + 27;
			G[u].push_back(v);
			G[v].push_back(u);
		}
		scanf("%lld%s%s", &x, s, e);
		if (isupper(s[0]))
			u = s[0] - 'A' + 1;
		else u = s[0] - 'a' + 27;
		if (isupper(e[0]))
			v = e[0] - 'A' + 1;
		else v = e[0] - 'a' + 27;
		dijkstra(v, u, x, 52);
		printf("Case %d:\n", cas++);
		printf("%lld\n", dis[u]);
		printf("%c", s[0]);
		int cur = u;
		while (cur != v) {
			int Min = 100;
			for (int j = 0; j < G[cur].size(); j++) {
				ll tmp;
				if (G[cur][j] < 27)
					tmp = (ll) ceil(dis[cur]/20.0);
				else tmp = 1;
				if (dis[cur]-tmp == dis[G[cur][j]] && Min > G[cur][j])
					Min = G[cur][j];
			}
			cur = Min;
			printf("-%c", cur<27?(cur-1+'A'):(cur-27+'a'));
		}
		printf("\n");
	}
	return 0;
}

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

时间: 2024-10-13 15:12:06

UVA - 10537 The Toll! Revisited (最短路变形逆推)的相关文章

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

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

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

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

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

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

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 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

URAL 1934 Black Spot --- 简单最短路变形

边权为1,在维护最短路的同时维护p值最小,我直接存的(1-p),即不遇见的概率,要使得这个值最大. #include <iostream> #include <cstdlib> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #includ

UVA - 1416 Warfare And Logistics (最短路)

Description The army of United Nations launched a new wave of air strikes on terroristforces. The objective of the mission is to reduce enemy's logistical mobility. Each airstrike will destroy a path and therefore increase the shipping cost of the sh

UESTC 915 方老师的分身II --最短路变形

即求从起点到终点至少走K条路的最短路径. 用两个变量来维护一个点的dis,u和e,u为当前点的编号,e为已经走过多少条边,w[u][e]表示到当前点,走过e条边的最短路径长度,因为是至少K条边,所以大于K条边的当做K条边来处理就好了.求最短路的三个算法都可以做,我这里用的是SPFA,比较简洁. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #incl

zoj 1655 Transport Goods (最短路变形)

Transport Goods Time Limit: 2 Seconds      Memory Limit: 65536 KB The HERO country is attacked by other country. The intruder is attacking the capital so other cities must send supports to the capital. There are some roads between the cities and the