【UVa】10537 Toll! Revisited 最短路


Toll! Revisited

Input: Standard Input

Output: Standard Output

Time Limit: 1 Second

 

Sindbad the Sailor sold 66 silver spoons to the Sultan ofSamarkand. The selling was quite easy; but delivering was complicated. Theitems 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 villagewas simply one item. The toll for entering a town was one piece per 20 items carried. For example, to entera town carrying70 items, you had to pay 4items as toll. The towns and villages were situated strategically betweenrocks, 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 cheapestroute) is a real challenge. The best route depends upon the number of itemscarried. For numbers up to 20,villages and towns charge the same. For large numbers of items, it makes senseto 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 deliveredto 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 acheapest route. You will also have to find the cheapest route. If there is morethan 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 road map followed by the delivery details.

 

The first line of the road map 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 road map 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 road map 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


Orignal Problem: ACM ICPC World Finals 2003, Enhanced by SM, Member of EPP



题目大意:

运送货物需要缴纳过路费。进入一个村庄时需要缴纳一个单位的货物,进入一个城镇时每20个货物中就要上缴1个单位的货物。现在给你起点和终点,以及最后至少需要运到终点的货物的数量,你的任务是选择一条缴纳过路费最少的路线。

其中小写字母表示村庄,大写字母表示城镇,道路是双向的,大写字母的字典序比小写字母的小。如果有多条过路费最少的路线,输出字典序最小的。


题目分析:

本题可以用最短路算法解决。

不过是从终点向起点推,通过当前结点u的最小需要货物量推出下一个结点v的最小需要货物量。

cost[v] = cost[u] + ( cost[u] - 1 ) / 19 + 1 ;

字典序就更加方便了,倒着来的路,则每次遇到的点都是关键点,遇到花费相同时判断之前保存的前驱,以及刚来到这个结点的前驱,比较取最小就行了。

不要忘记用long long 。

PS:为什么我写的代码总是比别人长那么多= =||


代码如下:


#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std ;

#define clear( A , X ) memset ( A , X , sizeof A )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define FF( i , a , b ) for ( int i = a ; i <= b ; ++ i )

typedef long long LL ;
typedef LL type_d ;
const int maxN = 1005 ;
const int maxQ = 100005 ;
const int maxH = 100005 ;
const int maxE = 100005 ;
//const int oo = 0x3f3f3f3f ;

struct Heap {
	int num ;
	type_d d ;
	Heap () {}
	Heap ( type_d D , int Num ) :
		d(D) , num(Num) {}
} ;

struct Edge {
	int v , n , w ;
	Edge () {}
	Edge ( int V , int W , int N ) :
		v(V) , w(W) , n(N) {}
} ;

struct Priority_Queue {
	Heap heap[maxH] ;
	int top ;
	
	void swap ( Heap &a , Heap &b ) {
		Heap  tmp ;
		tmp =   a ;
		a   =   b ; 
		b   = tmp ;
	}
	
	int cmp ( const Heap a , const Heap b ) {
		return a.d < b.d ;
	}
	
	void Clear () {
		top = 0 ;
	}
	
	int Empty () {
		return 0 == top ;
	}
	
	void Push ( type_d d , int num ) {
		heap[top] = Heap ( d , num ) ;
		int o = top ++ , p = ( o - 1 ) >> 1 ;
		while ( o && cmp ( heap[o] , heap[p] ) ) {
			swap ( heap[o] , heap[p] ) ;
			o = p , p = ( o - 1 ) >> 1 ;
		}
	}
	
	int Front () {
		return heap[0].num ;
	}
	
	void Pop () {
		heap[0] = heap[-- top] ;
		int o = 0 , p = o , l = o * 2 + 1 , r = o * 2 + 2 ;
		while ( 1 ) {
			if ( l < top && cmp ( heap[l] , heap[p] ) )
				p = l ;
			if ( r < top && cmp ( heap[r] , heap[p] ) )
				p = r ;
			if ( p == o )
				break ;
			swap ( heap[o] , heap[p] ) ;
			o = p , l = o * 2 + 1 , r = o * 2 + 2 ;
		}
	}
} ;

struct Dij {
	Priority_Queue Q ;
	Edge edge[maxE] ;
	int adj[maxN] , cntE ;
	int done[maxN] ;
	type_d d[maxN] ;
	//int p[maxN] ;
	int next[maxN] ;
	int patha[maxN] , pathb[maxN] ;
	
	void Addedge ( int u , int v , int w = 0 ) {
		edge[cntE] = Edge ( v , w , adj[u] ) ;
		adj[u] = cntE ++ ;
		edge[cntE] = Edge ( u , w , adj[v] ) ;
		adj[v] = cntE ++ ;
	}
	
	void Init () {
		cntE = 0 ;
		Q.Clear () ;
		clear ( d , -1 ) ;
		//clear ( p , -1 ) ;
		clear ( next , -1 ) ;
		clear ( adj , -1 ) ;
	}
	
	LL Cost ( LL x , int idx ) {
		if ( idx >= 26 )
			return x + 1 ;
		return x + ( x - 1 ) / 19 + 1 ;
	}
	
	int Encode ( char ch ) {
		if ( ch >= 'A' && ch <= 'Z' )
			return ch - 'A' ;
		return ch - 'a' + 26 ;
	}
	
	char DeEncode ( int ch ) {
		if ( ch < 26 )
			return ch + 'A' ;
		return ch - 26 + 'a' ;
	}
	
	void Dijkstra ( LL x , int s ) {
		clear ( done , 0 ) ;
		d[s] = x ;
		Q.Push ( d[s] , s ) ;
		while ( !Q.Empty () ) {
			int u = Q.Front () ;
			Q.Pop () ;
			if ( done[u] )
				continue ;
			done[u] = 1 ;
			LL cost = Cost ( d[u] , u ) ;
			for ( int i = adj[u] ; ~i ; i = edge[i].n ) {
				int v = edge[i].v ;
				if ( d[v] == -1 || d[v] > cost ) {
					next[v] = u ;
					d[v] = cost ;
					Q.Push ( d[v] , v ) ;
				}
				else if ( d[v] == cost && u < next[v] )
					next[v] = u ;
			}
		}
	}
	
	void Print ( int x ) {
		while  ( ~next[x] ) {
			printf ( "%c-" , DeEncode ( x ) ) ;
			x = next[x] ;
		}
		printf ( "%c\n" , DeEncode ( x ) ) ;
	}
} ;

Dij D ;

void work () {
	int cas = 0 ;
	int n , m ;
	LL x ;
	int st , ed ;
	char s[2][5] ;
	while ( ~scanf ( "%d" , &n ) && n != EOF ) {
		D.Init () ;
		REP ( i , n ) {
			scanf ( "%s%s" , s[0] , s[1] ) ;
			D.Addedge ( D.Encode ( s[0][0] ) , D.Encode ( s[1][0] ) ) ;
		}
		scanf ( "%lld%s%s" , &x , s[0] , s[1] ) ;
		st = D.Encode ( s[0][0] ) ;
		ed = D.Encode ( s[1][0] ) ;
		D.Dijkstra ( x , ed ) ;
		printf ( "Case %d:\n" , ++ cas ) ;
		printf ( "%lld\n" , D.d[st] ) ;
		D.Print ( st ) ;
	}
}

int main () {
	work () ;
	return 0 ;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值