题目 ID :L1-049
题目分数 :20 分
语言:Java / Python
题目描述
天梯赛每年有大量参赛队员,要保证同一所学校的所有队员都不能相邻,分配座位就成为一件比较麻烦的事情。
为此我们制定如下策略:
- 假设某赛场有 N 所学校参赛
- 第 i 所学校有 M[i] 支队伍,每队 10 位参赛选手
- 每校选手排成一列纵队,第 i+1 队的选手排在第 i 队选手之后
- 从第 1 所学校开始,各校的第 1 位队员顺次入座,然后是各校的第 2 位队员......以此类推
- 如果最后只剩下 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 号座位开始逐个安排:
-
数据结构:
students[i]:记录第 i 个学校所有队员的座位号列表seatSchool[j]:记录第 j 号座位分配给了哪个学校
-
分配逻辑:
- 遍历每个学校,如果该学校还有学生没安排座位
- 检查当前座位的前一个座位是否已被同校学生占用
- 若前一个不是本校 → 正常安排到当前座位,座位号 +1
- 若前一个是本校 → 跳到下下个座位安排,座位号 +2
-
终止条件:所有学校的学生都被安排完毕
-
输出格式 :每所学校前输出
#X,每 10 个座位号换一行
代码实现
Java
java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] num = new int[n + 1];
for (int i = 1; i <= n; i++) {
num[i] = sc.nextInt();
}
List<int[]> students = new ArrayList<>(n + 1);
for (int i = 0; i <= n; i++) {
students.add(new int[0]);
}
int[] seatSchool = new int[100001];
int cnt = 1; // 当前座位号
while (true) {
boolean flag = true;
for (int school = 1; school <= n; school++) {
int need = num[school] * 10;
int[] cur = students.get(school);
if (cur.length < need) {
flag = false;
if (seatSchool[cnt - 1] != school) {
// 前一个座位不是本校,可以安排
seatSchool[cnt] = school;
int[] newArr = Arrays.copyOf(cur, cur.length + 1);
newArr[cur.length] = cnt;
students.set(school, newArr);
cnt++;
} else {
// 前一个是本校,跳到下下个座位
seatSchool[cnt + 1] = school;
int[] newArr = Arrays.copyOf(cur, cur.length + 1);
newArr[cur.length] = cnt + 1;
students.set(school, newArr);
cnt += 2;
}
}
}
if (flag) break;
}
StringBuilder sb = new StringBuilder();
for (int school = 1; school <= n; school++) {
sb.append("#").append(school).append("\n");
int[] seats = students.get(school);
for (int i = 0; i < seats.length; i++) {
if (i > 0 && i % 10 == 0) sb.append("\n");
if (i > 0 && i % 10 != 0) sb.append(" ");
sb.append(seats[i]);
}
sb.append("\n");
}
System.out.print(sb.toString());
}
}
Python
python
def solve():
n = int(input())
num = [0] + list(map(int, input().split()))
# 记录每个学校学生的座位号
students = [[] for _ in range(n + 1)]
id_school = [0] * 100001 # 记录每个座位是哪个学校
cnt = 1 # 当前座位号
while True:
flag = True
for school in range(1, n + 1):
# 如果该学校还有学生没安排座位
if len(students[school]) < num[school] * 10:
if id_school[cnt - 1] != school:
# 前一个座位不是本校,可以安排
id_school[cnt] = school
students[school].append(cnt)
cnt += 1
else:
# 前一个座位是本校,跳到下下个座位
id_school[cnt + 1] = school
students[school].append(cnt + 1)
cnt += 2
flag = False
if flag:
break
# 输出结果
for school in range(1, n + 1):
print(f"#{school}")
for i, seat in enumerate(students[school]):
if i > 0 and i % 10 == 0:
print()
if i > 0 and i % 10 != 0:
print(" ", end="")
print(seat, end="")
print()
if __name__ == "__main__":
solve()
运行验证
以样例输入验证:
输入:
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
复杂度分析
- 时间复杂度:O(T),其中 T 为最终分配的总座位数(不超过 100 × 10 × 10 = 10000)
- 空间复杂度:O(T),用于存储座位分配结果和临时数组
总结
本题关键在于模拟真实分配过程:
- 同一学校的队员不能相邻 → 需要检查前一个座位
- 最后只剩一校时隔位就坐 → 检查逻辑自动覆盖这种情况
- 按学校循环轮转安排 → 类似多路归并的思想
核心是理解"隔位就坐"规则在代码中表现为:若前一个座位已是本校,则当前座位跳过(cnt += 2)。