UVA - 10537 The Toll! Revisited dijkstra反向

该博客讲述了如何解决一个基于Dijkstra算法的最短路径问题,其中涉及城镇和村庄的入口通行费。问题要求找出从起点到终点携带商品的最低成本路径,城镇收费为携带物品的1/20,村庄收费为1单位。解决方案包括反转起点和终点来寻找起点所需的最小金额,并使用邻接表和前驱数组记录路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Sindbad the Sailor sold 66 silver spoons to the Sultan of Samarkand. The selling was quite easy; butdelivering was complicated. The items were transported over land, passing through several towns andvillages. Each town and village demanded an entry toll. There were no tolls for leaving. The toll forentering 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 4 items as toll. The towns and villageswere 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, youmust start with 76 spoons.Figure 2: The best route to reach X with 39 spoons, starting from A, is A→b→c→X, shown witharrows in the figure on the left. The best route to reach X with 10 spoons is A→D→X, shown in thefigure 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 (thecheapest route) is a real challenge. The best route depends upon the number of items carried. Fornumbers up to 20, villages and towns charge the same. For large numbers of items, it makes sense toavoid towns and travel through more villages, as illustrated in Figure 2.You must write a program to solve Sindbads 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 itemsrequired at the beginning of the journey that uses a cheapest route. You will also have to find thecheapest route. If there is more than one such route, print the lexicographically smallest one (A-n-d issmaller than a-n-d).InputThe input consists of several test cases. Each test case consists of two parts: the roadmap followed bythe 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 ineither 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 thestarting place, and a letter for the place of delivery. The roadmap is always such that the items can bedelivered.The last test case is followed by a line containing the number ‘-1’.OutputThe output consists of three lines for each test case. First line displays the case number, second lineshows the number of items required at the beginning of the journey and third line shows the pathaccording to the problem statement above. Actually, the path contains all the city/village names thatSindbad sees along his journey. Two consecutive city/village names in the path are separated by ahyphen.

喵的题目粘贴的屎一样,不管了,题目意思大概就是给一个图,节点分为大小字母,每经过一个大写节点会收取1/20的当前钱数,经过小写节点会收取1元,要求最后到达重点的钱数,问最少在起点带多少钱。

给终点求起点,第一反应就是起点终点互换求最短路。用邻接表保存,处理每到一个节点的所需金额即可。

用pre数组存一下前驱输出路径。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
const ll inf=1LL<<60;
char s1[2],s2[2];
vector<int> mp[210];
ll dis[210];
bool vis[210];
int pre[210];
ll sum;
ll calc(char x)
{
	if(islower(x)) return dis[x]+1;
	else
	{
		ll tmp=ceil(dis[x]*20*1.0/19);
		return tmp;
	}
}
void dijkstra(int start,int ed)
{
	for(int i=0;i<210;i++)
	{
		dis[i]=inf;
		vis[i]=0;
		pre[i]=-1;
	}
	dis[start]=sum;
	vis[start]=1;
	for(int i=0;i<mp[start].size();i++)
	{
		dis[mp[start][i]]=calc(start);
		pre[mp[start][i]]=start;
	}
	for(int i=0;i<200;i++)
	{
		ll minn=inf;
		int t=-1;
		for(int j=1;j<=200;j++)
		{
			if(!vis[j]&&dis[j]<minn)
			{
				minn=dis[j];
				t=j;
			}
		}
		if(t!=-1)
		{
			vis[t]=1;
			ll cost=calc(t);
			for(int j=0;j<mp[t].size();j++)
			{
				if(!vis[mp[t][j]]&&dis[mp[t][j]]>cost)
				{
					pre[mp[t][j]]=t;
					dis[mp[t][j]]=cost;
				}
			}
		}
	}
}
int main()
{
	int tt=0;
	int n;
	while(scanf("%d",&n)!=EOF&&n!=-1)
	{
		for(int i='A';i<='Z';i++)
            mp[i].clear();
        for(int i='a';i<='z';i++)
            mp[i].clear();
		for(int i=0;i<n;i++)
		{
			scanf("%s %s",s1,s2);
			mp[s1[0]].push_back(s2[0]);
			mp[s2[0]].push_back(s1[0]);
		}
		scanf("%d %s %s",&sum,s1,s2);
		dijkstra(s2[0],s1[0]);
		printf("Case %d:\n",++tt);
		printf("%lld\n",dis[s1[0]]);
		printf("%c",s1[0]);
		int u=s1[0];
		while(pre[u]!=-1)
		{
			u=pre[u];
			printf("-%c",u);
		}
		printf("\n");
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值