先按帮贡和输入顺序给可调整成员重新分配职位,再按职位、等级和输入顺序排序输出。
OJ: luogu
题目 ID: P1786
难度:普及-
标签:排序模拟结构体python
日期: 2026-07-15 21:48
题意
帮派成员有姓名、职位、帮贡和等级。帮主和副帮主职位不能调整;其他人先按帮贡从高到低、输入顺序从前到后排序,重新分配职位。最后按职位高低、等级从高到低、输入顺序从前到后输出。
思路
每个成员用字典保存:
python
name, role, contribution, level, index第一阶段:筛出可调整成员,排序关键字为:
python
(-contribution, index)然后按名额依次分配 HuFa、ZhangLao、TangZhu、JingYing、BangZhong。
第二阶段:全体成员排序,关键字为:
python
(role_rank[role], -level, index)其中 role_rank 表示职位从高到低的顺序。
Python 知识
/home/rainboy/mycode/hugo-blog/content/program_language/python/sorting_and_ordering.md:多关键字排序可以用元组作为key。/home/rainboy/mycode/hugo-blog/content/program_language/python/collections_toolkit.md:字典适合保存一条记录的多个字段。- 数字前加负号可以把升序排序变成降序效果。
- Python 排序稳定,但这里显式加入
index更清楚。
代码
python
role_rank = {
"BangZhu": 0,
"FuBangZhu": 1,
"HuFa": 2,
"ZhangLao": 3,
"TangZhu": 4,
"JingYing": 5,
"BangZhong": 6,
}
new_roles = (
["HuFa"] * 2
+ ["ZhangLao"] * 4
+ ["TangZhu"] * 7
+ ["JingYing"] * 25
)
n = int(input())
members = []
for index in range(n):
name, role, contribution, level = input().split()
members.append({
"name": name,
"role": role,
"contribution": int(contribution),
"level": int(level),
"index": index,
})
adjustable = [
member for member in members
if member["role"] != "BangZhu" and member["role"] != "FuBangZhu"
]
adjustable.sort(key=lambda member: (-member["contribution"], member["index"]))
for rank, member in enumerate(adjustable):
if rank < len(new_roles):
member["role"] = new_roles[rank]
else:
member["role"] = "BangZhong"
members.sort(key=lambda member: (
role_rank[member["role"]],
-member["level"],
member["index"],
))
for member in members:
print(member["name"], member["role"], member["level"])cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-27 00:00
* update_at: 2026-07-27 00:00
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 115;
int n;
// 成员结构体
struct Member {
char name[20]; // 姓名
char role[20]; // 职位
int contribution; // 帮贡
int level; // 等级
int idx; // 输入顺序
};
Member members[MAXN];
// 职位对应的排名值(越小职位越高)
int role_rank(char *role) {
if (strcmp(role, "BangZhu") == 0) return 0;
if (strcmp(role, "FuBangZhu") == 0) return 1;
if (strcmp(role, "HuFa") == 0) return 2;
if (strcmp(role, "ZhangLao") == 0) return 3;
if (strcmp(role, "TangZhu") == 0) return 4;
if (strcmp(role, "JingYing") == 0) return 5;
return 6; // BangZhong
}
// 阶段 1 排序:按帮贡降序,帮贡相同按输入顺序升序
bool cmp1(const Member &a, const Member &b) {
if (a.contribution != b.contribution)
return a.contribution > b.contribution;
return a.idx < b.idx;
}
// 阶段 2 排序:按职位排名升序->等级降序->输入顺序升序
bool cmp2(const Member &a, const Member &b) {
int ra = role_rank((char*)a.role);
int rb = role_rank((char*)b.role);
if (ra != rb) return ra < rb;
if (a.level != b.level) return a.level > b.level;
return a.idx < b.idx;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 0; i < n; i++) {
cin >> members[i].name >> members[i].role
>> members[i].contribution >> members[i].level;
members[i].idx = i;
}
// 新职位分配表
char new_roles[50][20] = {
"HuFa", "HuFa",
"ZhangLao", "ZhangLao", "ZhangLao", "ZhangLao",
"TangZhu", "TangZhu", "TangZhu", "TangZhu",
"TangZhu", "TangZhu", "TangZhu",
"JingYing", "JingYing", "JingYing", "JingYing",
"JingYing", "JingYing", "JingYing", "JingYing",
"JingYing", "JingYing", "JingYing", "JingYing",
"JingYing", "JingYing", "JingYing", "JingYing",
"JingYing", "JingYing", "JingYing", "JingYing",
"JingYing", "JingYing", "JingYing", "JingYing",
"JingYing", "JingYing"
};
int new_role_cnt = 38; // 2+4+7+25
// 筛选出可调整的成员(不是帮主和副帮主)
Member adj[MAXN];
int adj_cnt = 0;
for (int i = 0; i < n; i++) {
if (strcmp(members[i].role, "BangZhu") != 0 &&
strcmp(members[i].role, "FuBangZhu") != 0) {
adj[adj_cnt++] = members[i];
}
}
// 按帮贡排序
sort(adj, adj + adj_cnt, cmp1);
// 重新分配职位
for (int i = 0; i < adj_cnt; i++) {
if (i < new_role_cnt)
strcpy(adj[i].role, new_roles[i]);
else
strcpy(adj[i].role, "BangZhong");
}
// 把调整后的成员合并回原数组
int p = 0;
for (int i = 0; i < n; i++) {
if (strcmp(members[i].role, "BangZhu") == 0 ||
strcmp(members[i].role, "FuBangZhu") == 0) {
continue;
}
members[i] = adj[p++];
}
// 最终排序并输出
sort(members, members + n, cmp2);
for (int i = 0; i < n; i++) {
cout << members[i].name << " "
<< members[i].role << " "
<< members[i].level << "\n";
}
return 0;
}复杂度
成员数最多 110,排序复杂度是
总结
本题是典型的两阶段排序模拟:先重新分配职位,再按展示规则排序。把每个排序规则写成清楚的 key 元组即可。