1. 题目描述
在 Berland 进行了一场名为「Sleepyhead-2010」的快速入睡锦标赛,参赛选手数量为 n
,每场比赛有 2 名选手对战,最终 n * (n - 1) / 2
场比赛全部完成,每位选手都与其他选手各进行了一场比赛。
比赛规则:
- 入睡速度
p_j
较低 的选手获胜,即谁更晚入睡谁输掉比赛。 - 记录比赛结果的格式是
(x, y)
,表示x
击败了y
。 - 但由于秘书的失误,比赛记录 遗漏了一场比赛,需要找出该场比赛的对阵选手。
输入格式
- 第一行包含一个整数
n
(3 ≤ n ≤ 50) 表示选手人数。 - 接下来
n * (n - 1) / 2 - 1
行,每行包含两个整数x, y
(1 ≤ x, y ≤ n, x ≠ y),表示x
击败了y
。
输出格式
- 输出两个整数
x
和y
,表示遗漏的比赛(顺序无所谓,任意顺序均可)。
2. 示例解析
输入示例
4
4 2
4 1
2 1
3 1
输出示例
4 3
解析
- 参赛选手有
{1, 2, 3, 4}
。 - 已知比赛:
4
>2
4
>1
2
>1
3
>1
- 每位选手应有
n-1=3
场比赛:1
:已经对阵 2、3、4(无缺失)。2
:已经对阵 1、4,缺少 3。3
:已经对阵 1,缺少 2、4。4
:已经对阵 1、2,缺少 3。
由此得出 缺失比赛是 4 vs. 3,所以输出 4 3
或 3 4
均可。
3. C++ 代码(原始实现)
题目最初的 C++ 代码如下:
#include <cstdio>
#include <vector>
#include <set>
int main(){
int n;
scanf("%d", &n);
std::vector<std::set<int>> win(n);
std::vector<std::set<int>> lose(n);
for(int p = 1; p < n * (n - 1) / 2; p++){
int x, y;
scanf("%d %d", &x, &y);
--x; --y;
win[x].insert(y);
lose[y].insert(x);
}
int a(-1), b(-1);
for(int p = 0; p < n; p++){
if(win[p].size() + lose[p].size() >= n - 1) continue;
if(a < 0) a = p;
else if(b < 0) b = p;
}
for(int p = 0; p < n; p++){
if(win[a].count(p) && lose[b].count(p)) break;
else if(lose[a].count(p) && win[b].count(p)){
std::swap(a, b);
break;
}
}
printf("%d %d\n", a + 1, b + 1);
return 0;
}
代码分析:
- 采用
set
记录胜负关系,win[i]
记录i
击败的选手,lose[i]
记录i
败给的选手。 - 遍历所有选手,找出比赛数小于
n-1
的两个选手a
和b
。 - 根据已知胜负关系,判断 a 是否应当击败 b,并调整顺序。
- 输出 遗漏的比赛对阵选手。
4. Python 代码实现
Python 版本的实现如下:
def find_missing_match():
n = int(input()) # 读取选手人数
win = [set() for _ in range(n)]
lose = [set() for _ in range(n)]
# 读取比赛结果
for _ in range(n * (n - 1) // 2 - 1):
x, y = map(int, input().split())
x -= 1 # 转换为 0-based 索引
y -= 1
win[x].add(y)
lose[y].add(x)
a, b = -1, -1
# 找到少打一场的两个选手
for p in range(n):
if len(win[p]) + len(lose[p]) < n - 1:
if a == -1:
a = p
else:
b = p
# 确定 a vs. b 的正确顺序
for p in range(n):
if p in win[a] and p in lose[b]:
break
elif p in lose[a] and p in win[b]:
a, b = b, a
break
print(a + 1, b + 1) # 输出 1-based 结果
if __name__ == "__main__":
find_missing_match()
5. Python 代码优化
相比 C++,Python 代码更加简洁,进一步优化版本如下:
def find_missing_match():
n = int(input())
matches = set()
for _ in range(n * (n - 1) // 2 - 1):
x, y = map(int, input().split())
matches.add((x, y))
for i in range(1, n + 1):
for j in range(i + 1, n + 1):
if (i, j) not in matches and (j, i) not in matches:
print(i, j)
return
if __name__ == "__main__":
find_missing_match()
优化点
- 直接使用
set
存储比赛记录,减少存储win[]
和lose[]
的额外开销。 - 遍历所有可能的比赛,直接找到缺失比赛。
6. 复杂度分析
方法 | 时间复杂度 | 空间复杂度 |
---|---|---|
win[]/lose[] 版本 | O(n²) | O(n²) |
set() 存储比赛记录 | O(n²) | O(n²) |
在 n ≤ 50
的范围内,这两种方法均可高效运行。
7. 总结
- 采用 集合存储比赛记录 是解决问题的关键。
- Python 的
set
和list
操作 使代码更加简洁。 - 直接 遍历所有可能的比赛 可以找到缺失比赛,避免额外数据结构存储。