PTA(Programming Teaching Assistant)平台上的L1-049题"天梯赛座位分配"是一道典型的算法设计题目,主要考察参赛者对数组操作和逻辑控制的理解能力。这类题目在天梯赛初赛中经常出现,作为筛选基础扎实选手的重要关卡。
题目核心要求是模拟一个多学校参赛情况下的座位分配系统。具体来说,给定N个参赛学校,每个学校有若干支队伍(每队3人),需要将所有选手按照特定规则安排在连续的座位区域。最关键的分配规则是:同一学校的选手不能坐在相邻位置,除非该校所有选手都已安排完毕。
面对这种需要处理多组数据的题目,我首先考虑使用结构体数组来存储每个学校的信息:
c复制struct School {
int team_num; // 该校队伍数量
int remain; // 剩余未分配选手数
int last_pos; // 上次分配的位置
};
这种设计可以方便地跟踪每个学校的分配状态。remain字段在分配过程中会动态变化,而last_pos则用于检查相邻分配的限制条件。
我采用的算法流程如下:
初始化阶段:
分配阶段:
输出阶段:
分配座位的核心代码如下:
c复制while (total > 0) {
int assigned = 0;
// 第一轮尝试:找不违反相邻规则的学校
for (int i = 0; i < N; i++) {
if (schools[i].remain == 0) continue;
if (schools[i].last_pos == -1 ||
pos - schools[i].last_pos > 1) {
// 分配座位
result[i].push_back(pos);
schools[i].last_pos = pos;
schools[i].remain--;
total--;
pos++;
assigned = 1;
break;
}
}
// 如果第一轮没分配成功,强制分配剩余最多的学校
if (!assigned) {
int max_remain = 0, idx = -1;
for (int i = 0; i < N; i++) {
if (schools[i].remain > max_remain) {
max_remain = schools[i].remain;
idx = i;
}
}
if (idx != -1) {
result[idx].push_back(pos);
schools[idx].last_pos = pos;
schools[idx].remain--;
total--;
pos++;
}
}
}
在实际编码中,有几个边界情况需要特别注意:
虽然题目数据规模不大,但养成优化习惯很重要:
PTA平台对输出格式要求严格,需要注意:
示例输出代码:
c复制for (int i = 0; i < N; i++) {
printf("#%d\n", i + 1);
for (int j = 0; j < result[i].size(); j++) {
printf("%4d", result[i][j]);
if ((j + 1) % 10 == 0 || j == result[i].size() - 1)
printf("\n");
}
}
根据我的参赛和教学经验,这道题常见错误包括:
曾经有个学生在实现时遇到了奇怪的结果错误。经过排查,发现是因为他在强制分配时没有更新last_pos,导致后续分配仍然认为该学校上次分配位置很远。这个bug在小数据时不易发现,但在大数据时会导致分配顺序完全错误。
修正方法是确保每次分配(无论是正常分配还是强制分配)都要更新last_pos:
c复制// 错误代码
if (!assigned) {
result[idx].push_back(pos);
schools[idx].remain--; // 忘记更新last_pos
total--;
pos++;
}
// 正确代码
if (!assigned) {
result[idx].push_back(pos);
schools[idx].last_pos = pos; // 必须更新
schools[idx].remain--;
total--;
pos++;
}
实际问题中可能需要考虑更多限制:
这些情况下,可能需要使用更复杂的数据结构,如优先队列、图算法等。
对于更大规模的题目,可以考虑:
这类算法在实际中有多种应用:
理解这类基础算法有助于解决更复杂的实际问题。比如在分布式系统中,类似的思路可以用于任务调度,避免同一用户的任务集中在某些节点。