题解:洛谷 P1786 帮贡排序

【题目来源】

洛谷:P1786 帮贡排序 - 洛谷(luogu.com.cn)

【题目描述】

目前帮派内共最多有一位帮主,两位副帮主,两位护法,四位长老,七位堂主,二十五名精英,帮众若干。

现在 absi2011 要对帮派内几乎所有人的职位全部调整一番。他发现这是个很难的事情。于是要求你帮他调整。

他给你每个人的以下数据:

他的名字(长度不会超过 \(30\)),他的原来职位,他的帮贡,他的等级。

他要给帮贡最多的护法的职位,其次长老,以此类推。

可是,乐斗的显示并不按帮贡排序而按职位和等级排序。

他要你求出最后乐斗显示的列表(在他调整过职位后):职位第一关键字,等级第二关键字。

注意:absi2011 无权调整帮主、副帮主的职位,包括他自己的(这不是废话么..)

他按原来的顺序给你(所以,等级相同的,原来靠前的现在也要靠前,因为经验高低的原因,但此处为了简单点省去经验。)

【输入】

第一行一个正整数 \(n\),表示星月家园内帮友的人数。

下面 \(n\) 行每行两个字符串两个整数,表示每个人的名字、职位、帮贡、等级。

【输出】

一共输出 \(n\) 行,每行包括排序后乐斗显示的名字、职位、等级。

【输入样例】

9
DrangonflyKang BangZhu 100000 66
RenZaiJiangHu FuBangZhu 80000 60
absi2011 FuBangZhu 90000 60
BingQiLingDeYanLei HuFa 89000 58
Lcey HuFa 30000 49
BangYou3 ZhangLao 1000 1
BangYou1 TangZhu 100 40
BangYou2 JingYing 40000 10
BangYou4 BangZhong 400 1

【输出样例】

DrangonflyKang BangZhu 66
RenZaiJiangHu FuBangZhu 60
absi2011 FuBangZhu 60
BingQiLingDeYanLei HuFa 58
BangYou2 HuFa 10
Lcey ZhangLao 49
BangYou1 ZhangLao 40
BangYou3 ZhangLao 1
BangYou4 ZhangLao 1

【核心思想】

  1. 问题分析:给定一个帮派成员列表,包含姓名、原职位、帮贡和等级。帮主和副帮主职位不可调整,其余成员需根据帮贡从高到低重新分配职位(职位名额固定:护法2人、长老4人、堂主7人、精英25人,其余为帮众)。最后要求按职位优先级(从高到低)等级从高到低输入顺序排序并输出。本质是一个多关键字排序 + 职位分配问题。

  2. 算法选择

    • 两次排序
      • 第一次排序:对除帮主和副帮主外的成员按帮贡降序、输入顺序升序排序,然后按固定名额分配职位(护法、长老、堂主、精英、帮众)。
      • 第二次排序:对所有成员按职位优先级(帮主→副帮主→护法→长老→堂主→精英→帮众)、等级降序、输入顺序升序排序,输出。
    • 职位优先级编码:使用函数 sti(zw) 将职位映射为数字(0~6),便于排序比较。
  3. 关键步骤

    • 读入:读取 \(n\) 和每个成员的信息,记录输入顺序(sx)。
    • 第一轮排序:对索引从 3 到 \(n-1\) 的成员(即除帮主和副帮主外)按帮贡降序、输入顺序升序排序。
    • 职位分配:遍历排序后的成员,根据其在列表中的位置(从 0 开始)分配职位:0~1 护法,2~5 长老,6~12 堂主,13~37 精英,其余帮众。
    • 第二轮排序:对所有成员按职位优先级升序、等级降序、输入顺序升序排序。
    • 输出:按排序后的顺序输出姓名、职位、等级。
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \log n)\),两次排序。
    • 空间复杂度:\(O(n)\)
  5. 多关键字排序与职位映射

    • 稳定排序:在帮贡相同时,按输入顺序排序,保证了原有的相对顺序。
    • 职位映射:将职位字符串转换为整数,使得排序时能按优先级比较。
    • 名额分配:帮主和副帮主固定,其余职位按名额依次分配。
    • 适用场景:这类“多级排序 + 名额分配”问题,常见于模拟题和系统设计类题目。

【算法标签】

普及 #模拟

【代码详解】

#include <bits/stdc++.h>
using namespace std;

// 定义结构体,表示每个人的信息
struct people
{
    string name; // 姓名
    string zw;   // 职位
    int bg;      // 贡献值
    int dj;      // 等级
    int sx;      // 序号(输入顺序)
} p[115]; // 最多115个人

// 比较函数1:用于排序贡献值和序号
bool cmp1(people p1, people p2)
{
    if (p1.bg != p2.bg) return p1.bg > p2.bg; // 贡献值高的排前面
    return p1.sx < p2.sx; // 贡献值相同,序号小的排前面
}

// 将序号转换为职位名称
string its(int n)
{
    if (n == 0) return "BangZhu";    // 序号0是帮主
    if (n <= 2) return "FuBangZhu";  // 序号1-2是副帮主
    if (n <= 4) return "HuFa";       // 序号3-4是护法
    if (n <= 8) return "ZhangLao";  // 序号5-8是长老
    if (n <= 15) return "TangZhu";  // 序号9-15是堂主
    if (n <= 40) return "JingYing"; // 序号16-40是精英
    return "BangZhong";             // 其余是帮众
}

// 将职位名称转换为序号
int sti(string s)
{
    if (s == "BangZhu") return 0;    // 帮主
    if (s == "FuBangZhu") return 1;  // 副帮主
    if (s == "HuFa") return 2;       // 护法
    if (s == "ZhangLao") return 3;   // 长老
    if (s == "TangZhu") return 4;    // 堂主
    if (s == "JingYing") return 5;   // 精英
    return 6;                        // 帮众
}

// 比较函数2:用于排序职位、等级和序号
bool cmp2(people p1, people p2)
{
    int tmp1 = sti(p1.zw), tmp2 = sti(p2.zw); // 将职位转换为序号
    if (tmp1 != tmp2) return tmp1 < tmp2; // 职位序号小的排前面
    if (p1.dj != p2.dj) return p1.dj > p2.dj; // 职位相同,等级高的排前面
    return p1.sx < p2.sx; // 等级相同,序号小的排前面
}

int main()
{
    int n; // 人数
    cin >> n; // 输入人数
    for (int i = 0; i < n; i++)
	{
        cin >> p[i].name >> p[i].zw >> p[i].bg >> p[i].dj; // 输入每个人的信息
        p[i].sx = i; // 记录输入顺序
    }

    // 对第4个人到第n个人按贡献值和序号排序(前3个人是帮主和副帮主,不参与排序)
    sort(p + 3, p + n, cmp1);

    // 根据排序后的序号分配职位
    for (int i = 0; i < n; i++)
        p[i].zw = its(i); // 将序号转换为职位名称

    // 对第4个人到第n个人按职位、等级和序号排序
    sort(p + 3, p + n, cmp2);

    // 输出每个人的信息
    for (int i = 0; i < n; i++)
        cout << p[i].name << " " << p[i].zw << " " << p[i].dj << endl;

    return 0;
}

【运行结果】

9
DrangonflyKang BangZhu 100000 66
RenZaiJiangHu FuBangZhu 80000 60
absi2011 FuBangZhu 90000 60
BingQiLingDeYanLei HuFa 89000 58
Lcey HuFa 30000 49
BangYou3 ZhangLao 1000 1
BangYou1 TangZhu 100 40
BangYou2 JingYing 40000 10
BangYou4 BangZhong 400 1
DrangonflyKang BangZhu 66
RenZaiJiangHu FuBangZhu 60
absi2011 FuBangZhu 60
BingQiLingDeYanLei HuFa 58
BangYou2 HuFa 10
Lcey ZhangLao 49
BangYou1 ZhangLao 40
BangYou3 ZhangLao 1
BangYou4 ZhangLao 1
posted @ 2026-08-31 09:25  团爸讲算法  阅读(11)  评论(0)    收藏  举报