PAT.A1087 All Roads Lead to Rome

本文介绍了一个算法问题,目标是在多个城市中找到通往罗马的最经济且快乐度最高的旅行路线。通过Dijkstra算法,我们能够找到成本最低且在成本相同时快乐度最大的路线,如果存在多条相同成本和快乐度的路线,则选择平均快乐度最高的那一条。

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

Indeed there are many different tourist routes from our city to Rome. You are supposed to find your clients the route with the least cost while gaining the most happiness.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers N (2≤N≤200), the number of cities, and K, the total number of routes between pairs of cities; followed by the name of the starting city. The next N−1 lines each gives the name of a city and an integer that represents the happiness one can gain from that city, except the starting city. Then K lines follow, each describes a route between two cities in the format City1 City2 Cost. Here the name of a city is a string of 3 capital English letters, and the destination is always ROM which represents Rome.

Output Specification:

For each test case, we are supposed to find the route with the least cost. If such a route is not unique, the one with the maximum happiness will be recommanded. If such a route is still not unique, then we output the one with the maximum average happiness -- it is guaranteed by the judge that such a solution exists and is unique.

Hence in the first line of output, you must print 4 numbers: the number of different routes with the least cost, the cost, the happiness, and the average happiness (take the integer part only) of the recommanded route. Then in the next line, you are supposed to print the route in the format City1->City2->...->ROM.

Sample Input:

6 7 HZH
ROM 100
PKN 40
GDN 55
PRS 95
BLN 80
ROM GDN 1
BLN ROM 1
HZH PKN 1
PRS ROM 2
BLN HZH 2
PKN GDN 1
HZH PRS 1

Sample Output:

3 3 195 97
HZH->PRS->ROM
#include<iostream>
#include<queue>
#include<map>
#include<string>
#include<cstring>
using namespace std;
const int maxn = 510;
const int INF = 100000000;
int n, m,st,ed;
string sts, c1s, c2s,tmp;
int d[maxn], edge[maxn][maxn], w[maxn], weight[maxn],pre[maxn],num[maxn],num2[maxn];
bool vist[maxn] = { false };
map<string,int> mp;
map<int, string> mp2;
//vector<int> pre[maxn];

void dijkstra(int s) {
	fill(d, d + maxn, INF);
	memset(w, 0, sizeof(w));
	memset(num, 0, sizeof(num));
	memset(num2, 0, sizeof(num2));
	for (int i = 0; i < n; i++)
		pre[i] = i;
	d[s] = 0;
	num[s] = 0;
	w[s] = weight[s];
	num2[s] = 1;
	for (int i = 0; i < n; i++) {
		int u = -1, min = INF;
		for (int j = 0; j < n; j++) {
			if (!vist[j] && d[j]<min) {
				min = d[j];
				u = j;
			}
		}
		if (u == -1) return;
		vist[u] = true;
		for (int v = 0; v < n; v++) {
			if (!vist[v] && edge[u][v] != INF) {
				if (d[v] > d[u] + edge[u][v]) {
					d[v] = d[u] + edge[u][v];
					w[v] = w[u] + weight[v];
					pre[v] = u;
					num[v] = num[u] + 1;
					num2[v] = num2[u];
				}
				else if (d[v] == d[u] + edge[u][v]) {
					num2[v] += num2[u];
					if (w[v] < w[u] + weight[v]) {
						w[v] = w[u] + weight[v];
						pre[v] = u;
						num[v] = num[u] + 1;
					}
					else if (w[v] == w[u] + weight[v]) {
						if (num[v] > num[u] + 1) {
							num[v] = num[u] + 1;
							pre[v] = u;
						}
					}
				}
			}
		}
	}
}
void dfs(int v) {
	if (v == 0) {
		cout << mp2[0];
		return;
	}
	dfs(pre[v]);
	cout << "->" << mp2[v];
}
int main() {
	scanf("%d%d", &n, &m);
	cin >> sts;
	mp[sts]=0;
	mp2[0] = sts;
	fill(edge[0], edge[0] + maxn * maxn, INF);
	for (int i = 1; i <n; i++) {
		cin >> tmp >> weight[i];
		mp[tmp] = i;
		mp2[i] = tmp;
	}
	ed = mp["ROM"];
	for (int i = 0; i < m; i++) {
		cin >> c1s >> c2s;
		cin >> edge[mp[c1s]][mp[c2s]];
		edge[mp[c2s]][mp[c1s]] = edge[mp[c1s]][mp[c2s]];
	}
	dijkstra(0);
	printf("%d %d %d %d\n", num2[ed], d[ed], w[ed], w[ed] / num[ed]);
	dfs(ed);
	return 0;
}

 

<think>我们根据用户需求,参考站内引用实现凯撒密码加密程序。特别注意:用户要求支持字符串和数字的加密。引用[2]提供了支持字母和数字的加密代码,使用字符串模块和translate映射表,这种方法简洁高效。引用[3]则使用循环逐个字符处理,支持大小写字母,但对数字的处理是直接拼接(即数字不加密),这不符合用户要求(用户明确要求加密字符串和数字)。用户需求:加密字符串和数字。因此,我们需要对数字也进行移位加密。注意:引用[2]的代码中,数字被当作一个整体进行了移位(比如数字0-9,偏移2变成2345678901),而引用[3]没有对数字加密。综合考虑,我们采用引用[2]的方法,因为其使用了字符串映射,支持字母(大小写)和数字的移位加密,且代码简洁。但需注意:引用[2]的代码中,数字的移位是在数字字符串内循环移位(即数字0-9共10个字符的移位),这符合凯撒密码的原理(对有限字符集进行移位)。因此,我们使用引用[2]的代码作为基础,并解释其工作原理。步骤:1.导入string模块2.定义加密函数,接收一个文本和一个整数偏移量n。3.准备小写字母、大写字母、数字字符串。4.将所有原始字符(待加密字符)拼接为:小写+大写+数字->before5.创建加密后的字符集:对于小写字母,将原小写字母字符串移位(前n个移到后面)形成新小写字符串;同样处理大写和数字。6.将加密后的字符集(小写移位串+大写移位串+数字移位串)拼接为after。7.用maketrans创建从before到after的映射表。8.使用translate方法将原文中的字符替换为映射表中的字符。注意:这种方法也支持非字母数字字符(如标点符号)吗?代码中只处理了字母和数字,其他字符不会出现在before中,因此会被原样保留(因为translate方法对于不在映射表中的字符保持原样)。这符合凯撒密码通常只加密字母数字的要求。用户要求加密字符串和数字,所以我们的代码已经满足。另外,用户没有要求解密,所以我们只实现加密。但为了完整性,我们可以同时实现加密和解密(解密其实就是用负偏移量或逆映射)。然而,用户问题只要求加密程序实现。因此,我们提供一个加密函数。但注意:引用[1]中提到凯撒密码的公式:E(x)=(x+n)%26(针对26个字母),对于数字我们可以类似地做:E(x)=(x+n)%10(但注意,这里x是数字字符的编码吗?实际上我们是把数字字符当作一个独立的10个字符的集合进行移位,所以对数字字符的移位操作是独立进行的,类似于对26个字母的操作,只不过基数是10)。我们根据引用[2]的代码风格,写一个加密函数,同时支持字母和数字,并且保留非字母数字不变。注意:引用[2]的代码中,数字移位的方式是:digit[n:]+digit[:n],例如n=2,则数字部分移位后为:'2345678901',也就是说,0被映射为2,1映射为3...9映射为1(因为9在移位2后是digit[2:]+digit[:2]->从2开始到结束,再加上0,1)。这样符合循环移位。因此,我们直接采用这种方式。代码实现如下:</think> ### 凯撒密码的实现 凯撒密码是一种经典的替代加密法,通过固定偏移量(密钥)将明文中的字母数字进行移位替换。根据您的需求,以下是支持字符串和数字的凯撒密码Python实现方案: ```python import string def caesar_encrypt(text, shift): """凯撒密码加密函数""" # 准备基本字符集:小写字母+大写字母+数字 chars = string.ascii_lowercase + string.ascii_uppercase + string.digits # 创建移位后的字符集 shifted_chars = ''.join([chars[(i + shift) % len(chars)] for i in range(len(chars))]) # 创建字符映射表 trans_table = str.maketrans(chars, shifted_chars) # 应用映射表进行加密 return text.translate(trans_table) ``` #### 工作原理: 1. **字符集定义**: - 小写字母:a-z(26字符) - 大写字母:A-Z(26字符) - 数字:0-9(10字符) - 总计62字符循环移位系统 2. **加密公式**: - 对于字符$x$在字符序列中的位置,加密后位置为: $$E(x) = (x + n)\ \text{mod}\ 62$$ - $n$为密钥(偏移量) #### 使用示例: ```python # 加密示例 plaintext = "Hello123" shift = 3 ciphertext = caesar_encrypt(plaintext, shift) print(f"加密结果: {ciphertext}") # 输出: Khoor456 # 解密示例(使用负偏移) decrypted = caesar_encrypt(ciphertext, -shift) print(f"解密结果: {decrypted}") # 输出: Hello123 ``` #### 特性说明: 1. 支持所有大小写字母和数字加密 2. 保留非字母数字字符(如标点、空格)不变 3. 完全可逆:加密后的文本可通过反向偏移解密 4. 密钥范围:1-61(62字符循环系统) > 数学原理:对于字符集大小为$m$的凯撒密码,密钥$n$的有效范围是$1$到$m-1$(本例$m=62$)。解密时使用$m-n$或$-n$均可实现逆变换[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值