冠亚季军比赛相关题目描述及相关代码

This commit is contained in:
2026-01-08 15:40:59 +08:00
parent 13b52220b0
commit e956855b2d
2 changed files with 174 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
# 获取输入的运动员的实力值
tmp = list(map(int, input("请输入运动员的实力值,以空格隔开").split()))
print(tmp)
class Sport:
def __init__(self, idx, strength):
self.idx = idx
self.strength = strength
# 将输入的运动员实力值转化为运动员集合
sports = []
for i in range(len(tmp)):
sports.append(Sport(i, tmp[i]))
# 晋级赛
def promote(sports, ans):
# 记录胜者组
win = []
# 记录败者组
fail = []
for i in range(1, len(sports), 2):
# 每组比赛序号大的运动员
major = sports[i]
# 每组比赛序号小的运动员
minor = sports[i-1]
if major.strength > minor.strength:
win.append(major)
fail.append(minor)
else:
win.append(minor)
fail.append(major)
# 如果晋级赛中,运动员个数为奇数,则最后一个运动员直接晋级
if len(sports)%2 != 0:
win.append(sports[-1])
# 依次头部压入失败组、胜者组
ans.insert(0, fail)
ans.insert(0, win)
# 当保留组超过3个的时候那么需要将超过部分去掉因为这部分已经无缘季军
while len(ans) > 3:
ans.pop()
# 算法入口
def getresult():
# 保留组ans只保留三个组冠军组、亚军组和季军组
ans = []
# 晋级赛
promote(sports, ans)
# 冠军组如果还不是一个人,那么还需要取出冠军组继续进行晋级赛
if len(ans[0]) != 1:
promote(ans.pop(0), ans)
# 冠军
first = ans[0][0].idx
# 亚军
second = ans[1][0].idx
# 季军
ans[2].sort(key=lambda x: (-x.strength, x.idx))
third = ans[2][0].idx
return f"{first} {second} {third}"
if __name__ == "__main__":
res = getresult()
print(res)

View File

@@ -0,0 +1,100 @@
# 比赛的冠亚季军
## 题目描述
有N3 ≤ N < 10000个运动员他们的id为0到N-1,他们的实力由一组整数表示。他们之间进行比赛需要决出冠亚军。比赛的规则是0号和1号比赛2号和3号比赛以此类推每一轮相邻的运动员进行比赛获胜的进入下一轮实力值大的获胜实力值相等的情况id小的情况下获胜轮空的直接进入下一轮。
## 输入描述
输入一行N个数字代表N的运动员的实力值(0<=实力值<=10000000000)。
## 输出描述
输出冠亚季军的id用空格隔开。
## 用例
| **输入** | 2 3 4 5 |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 输出 | 3 1 2 |
| 说明 | 第一轮比赛,<br/>id为0实力值为2的运动员和id为1实力值为3的运动员比赛1号胜出进入下一轮争夺冠亚军<br/>id为2的运动员和id为3的运动员比赛3号胜出进入下一轮争夺冠亚军<br/>冠亚军比赛3号胜1号<br/>故冠军为3号亚军为1号2号与0号比赛进行季军的争夺2号实力值为40号实力值2故2号胜出得季军。冠亚季军为3 1 2。 |
## 题目解析
本题主要考察逻辑分析
每轮晋级赛,都会将人数砍一半,因此本题不怕大数量级
在每轮晋级赛中,相邻的运动员组队进行比赛,比如有实力数组:[0,1,2,3,4,5,6,7,8]
其中0,1比赛2,3比赛4,5比赛6,7比赛其中实力较大者晋级去竞争冠亚季军对于8而言没有对手直接晋级
按照上面的逻辑,得到获胜组为:[1,3,5,7,8],失败组为:[0,2,4,6]
我们可以创建一个链表用于保存每轮的获胜组和失败组,但是需要保证获胜组在头部
即可得[1,3,5,7,8]->[0,2,4,6]
接下来去除链表头部组[1,3,5,7,8],继续进行晋级赛
其中1,3比赛5,7比赛8没有对手直接晋级
最后得到获胜组[3,7,8],失败组[1,5],将他们压入链表头部
[3,7,8] --> [1,5] --> [0,2,4,6]
接下来,取出链表头部组[3,7,8],继续进行晋级赛:
其中3、7比赛8没有对手直接晋级
最后得到获胜组[7,8],失败组[3],将他们压入链表头部
[7,8] --> [3] --> [1,5]
而链表头部的运动员个数还不为1即还有多个人竞争冠军
继续取出链表头部组[7,8],进行晋级赛
其中7、8比赛
最后得到获胜组[8],失败组[7],将他们压入链表头部
[8] --> [7] --> [3] --> [1,5]
此链表长度超过了3因此链表尾部的组失去了竞争季军的资格因此弹出尾部剩余
[8] --> [7] --> [3]
最后的冠军实力值8亚军实力值7季军实力值3
题目最后要求输出的是运动员id因此我们在一开始的时候可以定义一个运动员类属性有运动员的id和实力值。
这样最后输出就可以获取到运动员的id了。
还有一点需要注意的是:
最后一轮晋级赛,必然只有两个人,即分出冠军和亚军
倒数第二轮晋级赛只可能是4人或者3人如下图
<img src="file:///Users/wangyu/Library/Application%20Support/marktext/images/2026-01-06-11-25-58-image.png" title="" alt="" width="430">
<img src="file:///Users/wangyu/Library/Application%20Support/marktext/images/2026-01-06-13-35-34-image.png" title="" alt="" width="428">
如果倒数第二轮晋级赛有五人的话,是无法在下轮中产生冠军和亚军的
<img src="file:///Users/wangyu/Library/Application%20Support/marktext/images/2026-01-06-13-44-55-image.png" title="" alt="" width="463">
因此季军争夺组只会有2人或者1人因为如下图倒数第二轮晋级赛的失败者只有两人或者一人
<img src="file:///Users/wangyu/Library/Application%20Support/marktext/images/2026-01-06-13-51-36-image.png" title="" alt="" width="479">
<img title="" src="file:///Users/wangyu/Library/Application%20Support/marktext/images/2026-01-06-13-52-22-image.png" alt="" width="447">
因此,前面定义的链表,最终的形态如下:
第一个节点只有一个运动员(冠军),第二个节点只有一个运动员(亚军),第三个节点可能有一个,也可能有两个(季军争夺)。
因此,针对第三个节点,需要进行季军争夺,直接进行排序取第一个人即可,排序逻辑:
- 实力值大的获胜如果实力值相同则id值小的获胜。