2 条题解
-
0
题目描述
现在需要为本地业余篮球联赛的五支球队(蚂蚁队、桶队、猫队、运球者队、大象队,分别对应字母 A、B、C、D、E)确定季前赛的中位数排名。中位数排名的定义是:与所有给定排名的距离之和最小的排名。若存在多个这样的排名,选择按字母顺序最小的那个。
距离的计算方式:两个排名之间的距离等于所有球队对中相对顺序不同的对数。例如,排名 ACDBE 和 ABCDE 中,球队对 (B,C) 和 (B,D) 的顺序不同,因此距离为 2。
输入输出要求:
输入包含多个测试用例,每个用例第一行是整数 n(n≤100),随后 n 行是五个字母的排列(代表 n 个专家的排名)。 输出每个用例的中位数排名及其距离总和。若有多个解,输出字典序最小的。 解题思路
- 问题分析 我们需要枚举所有可能的五支球队的排列(共 5!=120 种可能),计算每个排列与所有输入排名的距离之和,找到总和最小的排列。若有多个最小值,选择字典序最小的排列。
- 关键步骤 2.1 生成所有可能的排列 五支球队的排列共有 120 种,可以通过预先生成所有排列并按字典序排序,以便后续处理时直接遍历并比较字典序。 2.2 计算两个排名之间的距离 对于两个排列 A 和 B,计算所有球队对 (i,j) 中在 A 和 B 中顺序不同的对数。具体步骤如下:
对每个球队对 (i,j)(i≠j),检查在 A 中 i 是否在 j 前面,同时在 B 中 i 是否在 j 后面,或者反之。若顺序不同,则计数加 1。 2.3 枚举所有候选排列并计算总距离 遍历所有 120 种排列,对每个排列计算其与所有输入排名的距离之和。记录当前最小总距离及对应的排列。若遇到总距离相同的排列,比较字典序,保留较小的那个。 3. 实现细节 3.1 生成排列的字典序顺序 可以使用 Python 的itertools.permutations生成所有排列,然后将其转换为字符串形式(如 "ABCDE"),并按字典序排序,确保在枚举时按字典序顺序处理,以便在总距离相同时自动选择字典序最小的排列。 3.2 距离计算函数 定义一个函数distance(rank1, rank2),计算两个长度为 5 的字符串之间的距离。通过双重循环遍历所有球队对,比较它们在两个字符串中的顺序是否不同。 3.3 处理输入输出 读取每个测试用例的 n 个排名,对每个候选排列计算总距离,更新最小总距离和对应的最优排列。最后输出结果。 4. 复杂度分析 每个测试用例需要枚举 120 种排列,每个排列需要与 n 个输入排名计算距离。 计算两个排名的距离的时间复杂度为 O (5×4)=O (20)(因为共有 5×4/2=10 对球队,但双重循环遍历所有 i<j 的对共 10 次)。 总时间复杂度为 O (120×n×20) = O (2400n),对于 n≤100 来说,完全可行。 示例代码 python
import itertools def calculate_distance(rank1, rank2): distance = 0 for i in range(5): for j in range(i+1, 5): a = rank1[i] b = rank1[j] # 在rank2中查找a和b的位置 pos1 = rank2.index(a) pos2 = rank2.index(b) if (pos1 > pos2) != (i > j): distance += 1 return distance def find_median_ranking(input_ranks): # 生成所有可能的排列,按字典序排序 teams = ['A', 'B', 'C', 'D', 'E'] all_permutations = [''.join(p) for p in itertools.permutations(teams)] all_permutations.sort() # 确保按字典序处理 min_total = float('inf') best_rank = None for candidate in all_permutations: total = 0 for rank in input_ranks: total += calculate_distance(candidate, rank) if total < min_total or (total == min_total and candidate < best_rank): min_total = total best_rank = candidate return best_rank, min_total def main(): import sys input = sys.stdin.read().split() ptr = 0 while True: n = int(input[ptr]) ptr += 1 if n == 0: break input_ranks = [] for _ in range(n): rank = input[ptr] ptr += 1 input_ranks.append(rank) best, value = find_median_ranking(input_ranks) print(f"{best} is the median ranking with value {value}.") if __name__ == "__main__": main()
代码解释 calculate_distance函数:计算两个排名之间的距离,通过遍历所有球队对并比较顺序差异。 find_median_ranking函数:生成所有排列并按字典序排序,遍历每个候选排列,计算其与所有输入排名的总距离,更新最小总距离和最优排列(确保字典序最小)。 main函数:读取输入数据,处理每个测试用例,调用上述函数求解并输出结果。
该方法通过枚举所有可能的排列并按字典序处理,确保在总距离相同时选择字典序最小的解,满足题目要求。
-
0
题意分析
本题的核心是在给定的多个由字母 A、B、C、D、E 组成的球队排名(代表蚂蚁队、桶队、猫队、运球者队和大象队的排名)中,找到一个中位数排名。中位数排名的定义是与所有给定排名的距离之和最小的排名,其中两个排名之间的距离是指两队之间相对顺序不同的总对数。需要处理多个输入集,每个输入集先输入排名的数量 n,然后是 n 个具体的排名,以输入 0 表示所有输入结束。最终输出每个输入集对应的中位数排名及其值,若有多个中位数排名,输出按字母顺序排在前面的那个。
解题思路
- 输入处理:读取每个输入集的排名数量 n,然后依次读取 n 个由字母 A、B、C、D、E 组成的排名字符串,存储在数组
a
中。 - 生成所有可能的排名:使用
next_permutation
函数对初始排名字符串s = "ABCDE"
进行全排列,遍历所有可能的排名情况。 - 计算距离和:对于每个生成的排名
s
,遍历输入的 n 个排名a[i]
,对于每个a[i]
,再遍历其中的每一对字母(共C(5, 2) = 10
对),在当前生成的排名s
中找到这两个字母的位置tj
和tk
,若tj > tk
,则说明在这两个排名中这对字母的相对顺序不同,距离和count
加 1。计算完s
与所有输入排名的距离和count
后,与当前最小距离和js
比较。 - 更新中位数排名:若
count < js
,则更新最小距离和js
为count
,并将当前排名s
更新为中位数排名jg
。 - 输出结果:遍历完所有可能的排名后,输出中位数排名
jg
及其最小距离和js
,格式为ranking is the median ranking with value value.
。
复杂度分析
- 时间复杂度:
- 输入部分,读取 n 个排名,时间复杂度为 \(O(n)\),其中 n 是每个输入集中排名的数量。
- 生成所有可能的排名,
next_permutation
函数生成全排列的时间复杂度为 \(O(5!)\),对于每个生成的排名,需要计算与 n 个输入排名的距离,计算距离的过程中,对于每个输入排名有 \(C(5, 2) = 10\) 对字母需要比较,所以计算距离的时间复杂度为 \(O(n \times 10)\)。因此,总的时间复杂度为 \(O(5! \times n \times 10)\),在 n 不超过 100 的情况下,该算法在可接受的时间范围内。
- 空间复杂度:
- 存储输入的 n 个排名需要 \(O(n)\) 的空间,存储生成的排名以及中间变量等额外空间为常数级,所以总的空间复杂度为 \(O(n)\)。
代码实现
#include <iostream> #include <string> #include <algorithm> #include <cstdio> using namespace std; string a[108]; int main() { while (1) { int n; cin >> n; if (n == 0) { break; } for (int i = 0; i < n; i++) { cin >> a[i]; } string s = "ABCDE"; string jg = "ABCDE"; int js = 1000; do { int count = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < 5; j++) { for (int k = j + 1; k < 5; k++) { char x = a[i][j]; char y = a[i][k]; int tj, tk; for (int h = 0; h < 5; h++) { if (s[h] == x) { tj = h; } if (s[h] == y) { tk = h; } } if (tj > tk) { count++; } } } } if (count < js) { js = count; jg = s; } } while (next_permutation(s.begin(), s.end())); cout << jg << " is the median ranking with value " << js << "." << endl; } return 0; }
- 输入处理:读取每个输入集的排名数量 n,然后依次读取 n 个由字母 A、B、C、D、E 组成的排名字符串,存储在数组
- 1
信息
- ID
- 1039
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 2
- 上传者