目录
类型题特点分析
"球队排名" 这类题属于基础模拟类题型 (也常归为 "数据处理 / 排序类"),是蓝桥杯省赛 / 国赛中高频的基础题(分值 10~15 分),也是新手最容易拿分的题型。以下我将针对蓝桥杯的考试特点,汇总这类题的核心思路、应试模板、高频考点和避坑技巧。
这类题在蓝桥杯中通常有以下特点,也是得分关键:
- 题干长但逻辑简单:文字描述多(比如规则、输入输出格式),但无复杂算法(不用动态规划、图论等),核心是 "把现实规则翻译成代码";
- 输入输出格式严格:蓝桥杯判题是 "标准答案比对",格式错(多空格、少换行、顺序错)直接 0 分;
- 数据规模小:省赛中 n 通常≤1000,不用考虑性能优化,暴力循环即可;
- 核心考点:输入处理、数据封装、规则计算、多条件排序、格式化输出。
例题剖析
通常在足球联赛里,n 支球队要分主客场打循环赛,最后根据积分排名。
假设积分相同则按净胜球多少排名,净胜球多者排名靠前;
如果积分和净胜球都相同 ,再按总进球数多少排名,总进球数多者排名靠前。
假设不会出现积分、净胜球、总进球数都相同的球队。注意,净胜球 = 总进球数 − 总失球数 。赢一场积 3 分、平一场积 1 分、输一场积 0 分。
输入 一个足球联赛里所有比赛的比分 ,输出 n 支球队的排名。
输入格式输入数据第 1 行是一个正整数 n ,4≤n≤20,表示球队的数量。
接下来有 n 行,每行有 n 个数字,组成一个 n×n 的矩阵。
第 i 行、第 j 列存储第 i 支球队主场对阵第 j 支球队的比分,格式固定为 a:b,
a 和 b 均为整数,范围为 [0,20],a 为第 i 支球队的进球数。
对角线上为数字 0。
输出格式
输出 n 支球队的排名情况 ,即输出 n 行,第 1~n 行为 4 个整数,用空格隔开,分别表示第 1~n 名球队的序号(序号从 1 开始计)、积分、净胜球数、总进球数。

题目梳理
| 核心要素 | 具体规则 |
|---|---|
| 输入 | 1. 第一行输入整数n(球队数量,序号 1~n);2. 接下来n行,每行输入n个比分(空格分隔),对应 "主队 vs 第 1~n 号客队" 的比分,主队 vs 自己填0,其余为a:b格式(a = 主队进球,b = 客队进球) |
| 输出 | 按排名输出每支球队的:序号(1 起始)、积分、净胜球数、总进球数 |
| 核心规则 | 1. 积分计算:赢 3 分、平 1 分、输 0 分;2. 净胜球 = 总进球 - 总失球(单场净胜球 = 本场进球 - 本场失球,累加);3. 排序规则:积分降序 → 净胜球降序 → 总进球数降序 |
思路梳理
步骤 1:数据封装(定义 Team 类)
目的:把每支球队的 4 个关联属性(序号、积分、净胜球、总进球)封装在一起,避免数据错位;
核心逻辑:
类名:
Team;构造方法
__init__:接收球队序号(1 起始),初始化积分、净胜球、总进球为 0(未比赛时均为 0);实例属性:
number(序号)、points(积分)、net_goals(净胜球)、total_goals(总进球)。类(Class) :是 "球队" 的模板 / 蓝图,定义了 "一支球队应该有哪些属性(编号、积分、净胜球、总进球)",但模板本身不是具体的球队;
实例(Instance) :是根据模板创建的具体的某一支球队(比如 1 号队、2 号队),每个实例都有自己独立的属性值,互不干扰。
步骤 2:初始化球队列表
目的 :创建
n支球队的实例,序号从 1 到 n;核心逻辑:
读取输入的
n(球队数量);用列表推导式生成
teams列表:teams = [Team(i+1) for i in range(n)](i是 0 起始索引,i+1转为 1 起始序号)。把 "循环创建实例 + 添加到列表" 的逻辑浓缩成一行,把所有实例放进 teams 列表
步骤 3:读取比分并更新球队数据(双层循环)
目的:解析每一场比赛的比分,按规则更新两队的积分、净胜球、总进球;
核心逻辑:
外层循环(主队) :
for home_idx in range(n)(home_idx是 0 起始主队索引,对应home_idx+1号主队);
- 读取当前主队的
n个比分,拆分为列表matches(如['0', '2:1', '1:1', '3:0']);内层循环(客队) :
for away_idx in range(n)(away_idx是 0 起始客队索引,对应away_idx+1号客队);
跳过主队 vs 自己(
home_idx == away_idx),无实际比赛;解析比分:取出
matches[away_idx],拆分为home_goals(主队进球)、away_goals(客队进球);更新积分:
主队进球 > 客队:
teams[home_idx].points += 3;主队进球 < 客队:
teams[away_idx].points += 3;平局:两队各加 1 分;
更新净胜球:
主队净胜球 +=
home_goals - away_goals;客队净胜球 +=
away_goals - home_goals;更新总进球:
主队总进球 +=
home_goals;客队总进球 +=
away_goals。步骤 4:按规则排序球队
目的:按 "积分→净胜球→总进球" 降序排列,得到最终排名;
核心逻辑:
用
list.sort()方法,key参数传入匿名函数,通过 "负号" 实现降序:teams.sort(key=lambda x: (-x.points, -x.net_goals, -x.total_goals));(可选)若用自定义比较函数,需借助
functools.cmp_to_key转换(Python3)。步骤 5:输出排名结果
目的:按排序后的顺序,输出每支球队的 4 个核心信息;
核心逻辑:
遍历排序后的
teams列表;依次打印:球队序号、积分、净胜球、总进球(空格分隔)。
代码实现
python
# ===================== 第一步:定义Team类(数据封装) =====================
# 为什么要定义类?
# 每支球队有编号、积分、净胜球、总进球4个关联属性,用类可以把这些属性封装在一起,
# 避免用多个独立列表(比如nums=[], points=[])导致数据错位,且代码更易维护
class Team:
# __init__是类的构造方法,创建实例时自动执行,用于初始化属性
# 参数number:外部传入的球队编号(1起始),是创建球队的必要参数
def __init__(self, number):
self.n = number # 绑定球队编号:每支球队必须有唯一标识,创建时就确定
self.a = 0 # 初始化积分:未比赛时积分为0,后续按比赛结果更新
self.b = 0 # 初始化净胜球:未比赛时净胜球=进球-失球=0,后续更新
self.c = 0 # 初始化总进球数:未比赛时进球数为0,后续累加
# ===================== 第二步:定义主函数(核心逻辑) =====================
# 为什么要定义main函数?
# 把所有业务逻辑放在主函数里,代码结构更清晰,符合"单一入口"的编程习惯,
# 也方便后续扩展(比如加参数、加调用逻辑)
def main():
# -------------------- 1. 读取并初始化球队数量 --------------------
# input()读取控制台输入的字符串,int()转换为整数:题目要求球队数量是整数
n = int(input()) # 读取球队数量(比如4、5等,题目通常要求4≤n≤20)
# 为什么用列表推导式初始化球队?
# 替代手动循环append,代码更简洁;range(n)生成0~n-1的索引,+1转为1起始的球队编号
# 最终teams列表包含n个Team实例,teams[0]是1号队,teams[1]是2号队,以此类推
teams = [Team(i + 1) for i in range(n)] # 初始化n支球队,编号1~n
# -------------------- 2. 外层循环:遍历每一支主队 --------------------
# l是主队索引(0起始),对应l+1号主队:比如l=0→1号主队,l=1→2号主队
# 为什么要遍历主队?
# 输入格式是"每支主队的n场比赛比分",必须逐支读取每支主队的比分数据
for l in range(n):
# 读取当前主队的比分行,split()按任意空格拆分:
# 1. input()读取一行字符串(比如"0 2:1 1:1 3:0")
# 2. split()默认按任意数量空格拆分(适配用户多打/少打空格的情况),
# 避免用split(' ')导致多空格拆分出空字符串(比如"0 2:1"→['0','','2:1'])
matches = input().split() # 拆分后得到比分列表,如['0','2:1','1:1','3:0']
# -------------------- 3. 内层循环:遍历当前主队的每一支客队 --------------------
# i是客队索引(0起始),对应i+1号客队:比如i=1→2号客队,i=2→3号客队
# 为什么要双层循环?
# 每支主队要和n支客队比赛(含自己),双层循环覆盖n×n的比分矩阵
for i in range(n):
# 跳过"主队vs自己"的比赛:
# 比分矩阵中对角线位置(l=i)是自己打自己,无实际比赛,输入为0,无需处理
if l == i:
continue # 直接跳过当前循环,不执行后续代码,避免解析无效数据
# -------------------- 4. 解析单场比赛比分 --------------------
# 为什么用i作为matches的索引?
# matches列表的第i个元素,正好对应主队l vs 客队i的比分(输入格式约定),
# 无需手动维护idx变量,避免索引错位(比如漏写idx+=1)
score = matches[i]
# 容错:跳过非比分格式的输入(比如对角线外的0、或格式错误的"2-1")
# 为什么要做容错?
# 避免用户输入错误(比如把2:1写成2-1)导致后续split(':')报错,程序崩溃
if ':' not in score:
continue # 非a:b格式,跳过当前比赛的处理
# 拆分比分字符串为整数:
# split(':')把"2:1"拆分为['2','1'],map(int, ...)转为整数,
# 分别赋值给home_goals(主队进球)、away_goals(客队进球)
home_goals, away_goals = map(int, score.split(':'))
# -------------------- 5. 更新积分(核心业务规则) --------------------
# 足球联赛积分规则:赢3分、平1分、输0分
if home_goals > away_goals:
teams[l].a += 3 # 主队赢:给主队(teams[l])加3分
elif home_goals < away_goals:
teams[i].a += 3 # 客队赢:给客队(teams[i])加3分
else:
teams[l].a += 1 # 平局:主队加1分
teams[i].a += 1 # 平局:客队加1分
# -------------------- 6. 更新净胜球 --------------------
# 净胜球定义:总进球数 - 总失球数
# 主队净胜球:本场主队进球 - 本场客队进球,累加到球队净胜球属性
teams[l].b += (home_goals - away_goals)
# 客队净胜球:本场客队进球 - 本场主队进球,累加到球队净胜球属性
teams[i].b += (away_goals - home_goals)
# -------------------- 7. 更新总进球数 --------------------
# 总进球数:所有比赛的进球数累加,用于积分/净胜球相同时的排序
teams[l].c += home_goals # 主队总进球 += 本场进球
teams[i].c += away_goals # 客队总进球 += 本场进球
# -------------------- 8. 按规则排序球队 --------------------
# 为什么用lambda+负号排序?
# 1. sort()默认升序,负号实现降序(积分高的排前面)
# 2. 元组(-x.a, -x.b, -x.c)实现多条件排序:
# - 先按积分降序(-x.a),积分相同按净胜球降序(-x.b),
# - 净胜球相同按总进球数降序(-x.c),完全符合题目排名规则
teams.sort(key=lambda x: (-x.a, -x.b, -x.c))
# -------------------- 9. 输出排名结果 --------------------
# 遍历排序后的球队列表:按排名顺序输出每支球队的编号、积分、净胜球、总进球
# 为什么按这个顺序输出?题目要求输出格式为"球队编号 积分 净胜球 总进球"
for team in teams:
print(team.n, team.a, team.b, team.c)
# ===================== 第三步:程序入口 =====================
# 为什么要加这个判断?
# 当脚本被直接运行时(比如python xxx.py),__name__ == "__main__"为True,执行main();
# 当脚本被导入时(比如import xxx),不执行main(),符合模块复用的规范
if __name__ == "__main__":
main()
模板整理
python
# 蓝桥杯模拟类题通用模板(类封装版)
class Entity:
"""通用数据类:封装唯一标识+核心属性"""
def __init__(self, id):
self.id = id # 唯一标识(必写:球队编号/学生学号/商品ID)
self.attr1 = 0 # 属性1(积分/总分/销售额)
self.attr2 = 0 # 属性2(净胜球/数学成绩/销量)
self.attr3 = 0 # 属性3(总进球/语文成绩/单价)
def main():
# 步骤1:读取数量(蓝桥杯输入第一行通常是数量)
n = int(input())
# 步骤2:初始化实例列表(唯一标识从1开始)
entities = [Entity(i+1) for i in range(n)]
# 步骤3:读取并处理每行数据(外层循环:主体)
for main_idx in range(n):
# 读取一行数据,拆分(strip清理首尾空格,split按任意空格拆分)
data = input().strip().split()
# 内层循环:关联对象(客队/科目等)
for sub_idx in range(n):
# 跳过无效数据(如自己对自己)
if main_idx == sub_idx:
continue
# 步骤4:解析数据(根据题目修改)
item = data[sub_idx]
# 示例:解析比分(蓝桥杯输入无脏数据,可简化容错)
if ':' not in item:
continue
h, a = map(int, item.split(':'))
# 步骤5:按规则计算(核心:改这里!)
# 示例:积分计算
if h > a:
entities[main_idx].attr1 += 3
elif h < a:
entities[sub_idx].attr1 += 3
else:
entities[main_idx].attr1 += 1
entities[sub_idx].attr1 += 1
# 示例:净胜球计算
entities[main_idx].attr2 += (h - a)
entities[sub_idx].attr2 += (a - h)
# 示例:总进球计算
entities[main_idx].attr3 += h
entities[sub_idx].attr3 += a
# 步骤6:多条件排序(核心:改属性和排序方向!)
# 规则:attr1降序 → attr2降序 → attr3降序
entities.sort(key=lambda x: (-x.attr1, -x.attr2, -x.attr3))
# 步骤7:格式化输出(严格按题目要求!)
for e in entities:
# 示例:输出 标识 attr1 attr2 attr3(空格分隔)
print(e.id, e.attr1, e.attr2, e.attr3)
if __name__ == "__main__":
main()
变式举例
| 题型变种 | 核心修改点 | 示例排序规则 |
|---|---|---|
| 学生成绩排名 | ① 属性改为:id、总分、数学、语文;② 计算规则改为:总分 = 数学 + 语文 + 英语 | sort(key=lambda x: (-x.total, -x.math, x.chinese))(总分降序、数学降序、语文升序) |
| 商品销售排名 | ① 属性改为:id、销售额、销量、单价;② 计算规则改为:销售额 = 销量 × 单价 | sort(key=lambda x: (-x.sales, -x.volume))(销售额降序、销量降序) |
| 运动会团体排名 | ① 属性改为:id、总分、金牌数、银牌数;② 计算规则改为:总分 = 金牌 ×3 + 银牌 ×2 + 铜牌 ×1 | sort(key=lambda x: (-x.total, -x.gold, -x.silver)) |
| 员工薪资排名 | ① 属性改为:id、总薪资、基本工资、绩效;② 计算规则改为:总薪资 = 基本工资 + 绩效 - 社保 | sort(key=lambda x: (-x.salary, x.id))(薪资降序、编号升序) |
易错点整理
- 索引 / 编号混淆 :代码内用 0 起始索引,输出必须用 1 起始的 "唯一标识"(如
team.id),不要用main_idx+1(排序后索引会乱);- 排序方向错:题干说 "从高到低"= 降序(加负号),"从低到高"= 升序(不加负号);
- 输出格式错 :
- 题干要求 "空格分隔":用
print(a, b, c)(自动加空格),不要手动加print(a + ' ' + b)(会类型报错);- 题干要求 "每行一个":循环内直接 print,不要额外加
print('\n');- 数据类型错 :解析数字时必须转 int/float(如
h, a = map(int, item.split(':'))),蓝桥杯输入是字符串,直接用会报错;- 漏算规则:比如只算主队积分,漏算客队积分;只算总进球,漏算净胜球(解题前列规则清单,算完勾掉)。