帮贡排序

GitHub跳转原题关系图返回列表

先按帮贡和输入顺序给可调整成员重新分配职位,再按职位、等级和输入顺序排序输出。

OJ: luogu

题目 ID: P1786

难度:普及-

标签:排序模拟结构体python

日期: 2026-07-15 21:48

题意

帮派成员有姓名、职位、帮贡和等级。帮主和副帮主职位不能调整;其他人先按帮贡从高到低、输入顺序从前到后排序,重新分配职位。最后按职位高低、等级从高到低、输入顺序从前到后输出。

思路

每个成员用字典保存:

python
name, role, contribution, level, index

第一阶段:筛出可调整成员,排序关键字为:

python
(-contribution, index)

然后按名额依次分配 HuFaZhangLaoTangZhuJingYingBangZhong

第二阶段:全体成员排序,关键字为:

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,排序复杂度是 O(nlogn)O(n\log n),空间复杂度是 O(n)O(n)

总结

本题是典型的两阶段排序模拟:先重新分配职位,再按展示规则排序。把每个排序规则写成清楚的 key 元组即可。