L1-049 天梯赛座位分配(Python实现) 测试点全过

前言: {\color{Blue}前言:} 前言:

  • 本系列题使用的是,“PTA中的团体程序设计天梯赛——练习集”的题库,难度有L1、L2、L3三个等级,分别对应团体程序设计天梯赛的三个难度。
  • 更新取决于题目的难度,和学校的事情,但尽可能保证每日更新,若没更新次日补上。
  • 这道题说实话有一点难度,做了很长一段时间,思路其实很简单,但是细节很多,所以要测试点全过就和找bug一样
  • 我的方法可能不是最简单的,如有什么好的建议,欢迎各位CSDN的朋友告诉我

题目

天梯赛每年有大量参赛队员,要保证同一所学校的所有队员都不能相邻,分配座位就成为一件比较麻烦的事情。为此我们制定如下策略:假设某赛场有 N 所学校参赛,第 i 所学校有 M[i] 支队伍,每队 10 位参赛选手。令每校选手排成一列纵队,第 i+1 队的选手排在第 i 队选手之后。从第 1 所学校开始,各校的第 1 位队员顺次入座,然后是各校的第 2 位队员…… 以此类推。如果最后只剩下 1 所学校的队伍还没有分配座位,则需要安排他们的队员隔位就坐。本题就要求你编写程序,自动为各校生成队员的座位号,从 1 开始编号。

输入格式
输入在一行中给出参赛的高校数 N (不超过100的正整数);第二行给出 N 个不超过10的正整数,其中第 i 个数对应第 i 所高校的参赛队伍数,数字间以空格分隔。

输出格式:
从第 1 所高校的第 1 支队伍开始,顺次输出队员的座位号。每队占一行,座位号间以 1 个空格分隔,行首尾不得有多余空格。另外,每所高校的第一行按“#X”输出该校的编号X,从 1 开始。

输入样例:

3
3 4 2

输出样例:

#1
1 4 7 10 13 16 19 22 25 28
31 34 37 40 43 46 49 52 55 58
61 63 65 67 69 71 73 75 77 79
#2
2 5 8 11 14 17 20 23 26 29
32 35 38 41 44 47 50 53 56 59
62 64 66 68 70 72 74 76 78 80
82 84 86 88 90 92 94 96 98 100
#3
3 6 9 12 15 18 21 24 27 30
33 36 39 42 45 48 51 54 57 60

题解

  • 在开始看具体代码之前,先总结下大致思路,这道题的最大难点,其实就在输出这一块,我最先开始,想尝试直接用一个大的循环,去挨个输出这个结果,但是发现出现了一个关键问题,就是多出来的队伍的座位号,不好处理,然后我就转变了一下思路
  • 既然不好找到具体位置,那我就先那个大的列表把所有输出都揽括进来,再把座位号给装进去,最后按题目要求进行输出吗,即大致为三步:
    1. 建立一个能把所有输出装进去的列表列表,同时先加入高校编号
    1. 把座位号按题目要求装进结果列表
    1. 采用合适的方法输出结果列表

如果想先测试自己的代码,是不是可以过所有测试点,可以测试以下几组数据,看下是否可以达到预期效果:

1
1
3
2 2 2
3
1 2 2
N = int(input())  # 输入参赛的高校数 N
M = list(map(int, input().split()))  # 输入每所高校的参赛队伍数,以列表形式保存

# 第一步:建立一个能把所有输出装进去的列表列表,同时先加入高校编号
result = []  # 初始化结果列表

for i in range(1, N + 1):  # 遍历高校编号
    result.append("#" + str(i))  # 添加高校编号
    for j in range(M[i - 1]):
        result.append([0] * 10)  # 用列表的形式给座位号占位

# 第二步:把座位号按题目要求装进结果列表
"""
在装座位号之前,肯定得先知道每个高校的第一个队伍的第一个人,在结果列表中的位置,
而最好的标志就是高校编号在结果列表中的位置
所以我们需要先找到这么一个数据

然后将数据稍加分析,我们会发现:
每个高校的位置 = 上个高校的位置 + 上个高校的队伍数 + 1
而第一所高校的位置就是0,且没有上一所高校,
所以我们在初始化时,就把它加进去"""
university_location_in_result = [0]  # 初始化高校编码在结果中的位置

for i in range(1, N):
    university_location_in_result.append(university_location_in_result[i - 1] + M[i - 1] + 1)  # 这一步解析见上面注释

"""
上面是很明显必要的一步,
完成这一步后,我们开始对放入这一部进行分析,
想放入座位号,无非就是解决一个问题:
result[i][j] = ?,

这个 ? 肯定是最好解决的,
就是座位号,从1加到最大数,这一步肯定是最外层的“循环”

然后来讨论这个 i 和 j 都和哪些条件有关,
这里为了方便分析,我们先简化这个题目,并且使用不那么特殊的一个样例,

先将题目中的每队十人,看成每队只有两个人,
输入的样例为
3
1 3 2

那么通过上一步可以找到高校编号的位置,为别为0 2 6
然后模拟几步:
result[1][0] = 1 result[4][1] = 4 
result[3][0] = 2 result[5][1] = 5 result[4][0] = 7 result[4][1] = 9 result[5][0] = 11 result[5][1] = 13 
result[7][0] = 3 result[6][1] = 6 result[8][0] = 8 result[8][1] = 10 

不难发现 j 其实就是循环的每个队伍有多少人,
当每个高校的第一个队伍循环完的时候,j 就又重新开始循环了,

而到底要循环多少次,即轮数,则取决于队伍数最多的高校,
现在便可以确定第二层“循环”是轮数,
第三层“循环”是每队人数,

而一直变化的 i 则是最内层“循环”,
且 i = 高校编号位置 + 轮数 + 1,
所以最内层“循环"的是university_location_in_result

以上大致思路就解决了,但是有两个特殊点还没有考虑到:
1. 新一轮开始的时候,某一高校以及没有队伍了怎么办?
2. 队伍最多的那个高校,怎么使它多出来的队伍的位置,都不相邻?"""

"""
这里解决的问题一,
分析可得,当 轮数 = 某个高校的队伍数 的时候,
就不应该在对它的高校编号进行循环了,
所以这两个数据是同存亡,或者说相关联的,
而且我们这里又不好去处理原来的列表,

综上,我们将它们组成一个字典,
又因为,高校位置是肯定都不会一样的,
所以用它做 键 """

team_information = dict(zip(university_location_in_result, M))
# 也可以这么写:team_information = {team_location_in_result[i]:M[i] for i in range(N)}

seat_number = 1  # 初始化座位号

"""
这里解决的是问题二,
先把最多队伍高校的多余队伍找出来,
然后根据不同的情况进行处理"""
M_1 = [i for i in M if i != max(M)]  # 除开最大数的M列表

difference_value = 0  # 最大队伍数与第二大队伍书数之差

if len(M_1) == 0 and N == 1:
    difference_value = sum(M)  # 这是“只有一个高校”的情况
elif len(M_1) == len(M) - 1:
    difference_value = max(M) - max(M_1)  # 这是“只有一个队伍数最多的高校”的情况
    # ”其余情况“都等于0

rounds = 0  # 初始化轮数

for rounds in range(max(team_information.values())):  # 循环轮数
    if rounds in team_information.values():  # 当轮数等与某一高校数相同的时候,删除该高校信息
        team_information = {key: value for key, value in team_information.items() if value != rounds}
    if seat_number > (sum(M) - difference_value) * 10:  # 这里不处理多余的队伍,所以跳出去
        break
    for team_number in range(10):  # 循环每队人数
        for university_location in team_information.keys():  # 循环高校位置,并装入座位号
            result[university_location + 1 + rounds][team_number] = seat_number
            seat_number += 1
"""
这里也有一个特殊点,
就是当有多余队伍的高校,是最后一个高校的时候,
要多一个间隔"""
if max(M) == M[N - 1] and N != 1:
    seat_number += 1

"""
这是处理多余高校"""
for i in range(difference_value):
    for team_number in range(10):
        result[list(team_information.keys())[0] + 1 + rounds + i][team_number] = seat_number  # 这个等式不知道怎么来的可以调试看下数据就能明白了
        seat_number += 2

# 第三步:输出结果列表
"""
无非就两种元素类型,
就不同情况输出就可以了"""
for i in result:
    if isinstance(i, str):
        print(i)
    else:
        print(' '.join(map(str, i)))


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦生dwu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值