算法刷题【洛谷P1786】帮贡排序——代码量子纠缠运行?

博客介绍了如何处理一道涉及排序和职位调整的C++竞赛题目,通过创建结构体存储成员信息,使用cmp函数进行排序,并针对不同职位设定优先级。代码中特别处理了帮主和副帮主的特殊情况,然后对剩余成员按帮贡和输入顺序排序,最后输出调整后的列表。在调试过程中遇到了变量值异常的问题,博主提出了疑问并分享了完整代码。
摘要由CSDN通过智能技术生成

异想之旅:本人原创博客完全手敲,绝对非搬运,全网不可能有重复;本人无团队,仅为技术爱好者进行分享,所有内容不牵扯广告。本人所有文章仅在CSDN、掘金和个人博客(一定是异想之旅域名)发布,除此之外全部是盗文!


题目背景

在absi2011的帮派里,死号偏多。现在absi2011和帮主等人联合决定,要清除一些死号,加进一些新号,同时还要鼓励帮贡多的人,对帮派进行一番休整。

题目描述

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

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

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

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

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

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

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

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

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

输入格式

第一行一个数n,表示星月家园内帮友的人数。

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

输出格式

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

输入输出样例

In 1

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

Out 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

标题提到的细思极恐等会再说。

这道题就是一个残害竞赛生的排序啊……

首先存储每个成员的结构体如下

struct node {
    string name, zw;  // 名字,当前职位
    long long bg, dj, id;  // 帮贡,等级,输入顺序
} a[200], fbz[2];  // a存正常成员,fbz存储副帮主

首先帮主和副帮主不参与调整,所以对于帮主读取到之后可以直接输出,而副帮主两个输入之后比较一下谁的等级高先输出谁就行了(虽然这道题在这里数据不强,不比较副帮主也是可以ac的,洛谷题解里很多都没考虑副帮主的问题,甚至有直接读入前三行输出的)

所以在这里设计输入如下

long long n;
cin >> n;
for (long long i = 0; i < n; i++) {
    cin >> a[i].name >> a[i].zw >> a[i].bg >> a[i].dj;
    a[i].id = i;  // 输入的顺序,方便过后排序
    if (a[i].zw == "BangZhu") {
    	// 帮主直接输出
        cout << a[i].name << " " << a[i].zw << " " << a[i].dj << endl;
        // 帮主不存进a里面,所以i和n要--(下面副帮主同)
        i--;
        n--;
    } else if (a[i].zw == "FuBangZhu") {
    	// 副帮主先存进fbz数组,要比较两个副帮主的等级之后再输出
        fbz[fbzl++] = a[i];
        i--;
        n--;
    }
}
if (fbz[0].dj < fbz[1].dj) swap(fbz[0], fbz[1]);  // 看当前两个副帮主顺序是否正确
for (int i = 0; i < 2; i++)
    cout << fbz[i].name << " " << fbz[i].zw << " " << fbz[i].dj << endl;  // 完成副帮主输出

至此完成了数据输入和帮主、副帮主的处理。

除此三人之外的其他人按照帮贡第一关键字、输入顺序第二关键字排序,可以直接结构体+cmp函数+sort实现(虽然按帮贡排序后通常情况相同帮贡会保持先输入的在前面,但是为了保险还是进行双关键字吧)

对结构体进行排序的cmp函数如下

bool cmp(node x, node y) {
    if (x.bg != y.bg)
        return x.bg > y.bg;  // 帮贡不同帮贡大的在前
    else
        return x.id < y.id;  // 否则排输入顺序
}

很多人说不会cmp函数到底怎么设计,这里给大家一个很简单的理解:cmp函数的参数x和y,如果x在前y在后是正确的return 1,否则return 0,简单说就是问x在前y在后这个顺序对不对

具体可以看这篇文章 干货:详解C++ sort函数的cmp参数!_异想之旅的博客-CSDN博客 (如果帮到了你还不赶快三连!)

然后就是一个咋看咋好用的sort了

sort(a, a + n, cmp);

往下我这个方法不是最好的,也很有可能是这里的书写才导致了那个细思极恐的问题,但是作为结构体和sort的练习等还是不错的

我们再开一个结构体存储帮主和副帮主之外的职位:

struct Node {
    string name;
    long long cnt;
} zw[10];  // zw就是职位

然后在main函数开头写上这一段

zw[0].name = "HuFa";
zw[0].cnt = 2;
zw[1].name = "ZhangLao";
zw[1].cnt = 4;
zw[2].name = "TangZhu";
zw[2].cnt = 7;
zw[3].name = "JingYing";
zw[3].cnt = 25;
zw[4].name = "BangZhong";
zw[4].cnt = 100000000;

众所周知,sort函数可以排数组的片段

所以我们首先为相同职位的再写一个cmpp函数

bool cmpp(node x, node y) {
    if (x.dj != y.dj)
        return x.dj > y.dj;
    else
        return x.id < y.id;
}

和上面的cmp类似,不再赘述,就是要注意因为等级相同还是按照输入顺序,所以不要忘了id的比较

最终的排序和输出,看注释

long long l = 0, i;
for (i = 0; i < 4; i++) {  // 完成除帮众外的排序和输出
    if (n - l >= zw[i].cnt) {
    	// 分析可知从数组索引l(含)到索引l + zw[i].cnt(不含)是当前职位的所有人
        sort(a + l, a + l + zw[i].cnt, cmpp);  // 按照等级和输入顺序排序
        for (long long j = l; j < l + zw[i].cnt; j++)
            cout << a[j].name << " " << zw[i].name << " " << a[j].dj << endl;  // 输出
        l += zw[i].cnt;  // 左指针自增,在此之前的都处理完了
    } else
        break;  // 如果人数不足以分配完当前职位了就跳出
}
if (n - l > 0) {  // 还有没分配的人
    sort(a + l, a + n, cmpp);  // 排序剩下的没分配的所有人
    for (long long j = l; j < n; j++)
        cout << a[j].name << " " << zw[i].name << " " << a[j].dj << endl;
}

这个程序在对于帮众的处理是没有bug的,自己尝试理解一下,实在不懂评论区提问我会解答

然后就附上完整的ac代码吧(我知道你就是奔着这里点开这篇文章的不是吗)

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

struct node {
    string name, zw;
    long long bg, dj, id;
} a[200], fbz[2];

struct Node {
    string name;
    long long cnt;
} zw[10];

long long fbzl = 0;

bool cmp(node x, node y) {
    if (x.bg != y.bg)
        return x.bg > y.bg;
    else
        return x.id < y.id;
}

bool cmpp(node x, node y) {
    if (x.dj != y.dj)
        return x.dj > y.dj;
    else
        return x.id < y.id;
}

int main() {
    zw[0].name = "HuFa";
    zw[0].cnt = 2;
    zw[1].name = "ZhangLao";
    zw[1].cnt = 4;
    zw[2].name = "TangZhu";
    zw[2].cnt = 7;
    zw[3].name = "JingYing";
    zw[3].cnt = 25;
    zw[4].name = "BangZhong";
    zw[4].cnt = 100000000;

    long long n;
    cin >> n;
    for (long long i = 0; i < n; i++) {
        cin >> a[i].name >> a[i].zw >> a[i].bg >> a[i].dj;
        a[i].id = i;
        if (a[i].zw == "BangZhu") {
            cout << a[i].name << " " << a[i].zw << " " << a[i].dj << endl;
            i--;
            n--;
        } else if (a[i].zw == "FuBangZhu") {
            fbz[fbzl++] = a[i];
            i--;
            n--;
        }
    }
    if (fbz[0].dj < fbz[1].dj) swap(fbz[0], fbz[1]);
    for (int i = 0; i < 2; i++)
        cout << fbz[i].name << " " << fbz[i].zw << " " << fbz[i].dj << endl;

    sort(a, a + n, cmp);
    long long l = 0, i;
    for (i = 0; i < 4; i++) {
        if (n - l >= zw[i].cnt) {
            // cout << i << zw[i].name << zw[i].cnt << endl;
            sort(a + l, a + l + zw[i].cnt, cmpp);
            for (long long j = l; j < l + zw[i].cnt; j++)
                cout << a[j].name << " " << zw[i].name << " " << a[j].dj
                     << endl;
            l += zw[i].cnt;
        } else
            break;
    }
    if (n - l > 0) {
        sort(a + l, a + n, cmpp);
        for (long long j = l; j < n; j++)
            cout << a[j].name << " " << zw[i].name << " " << a[j].dj << endl;
    }

    return 0;
}

细思极恐的就是

在我调试程序时

第76行输出的两个i居然不一样!

而且访问不到zw数组中的cnt!

并且似乎不是所有电脑都出现这样的表现(xth同学试了似乎没问题?)

代码放这里了

高人请指点,必有重谢!!!!

/*输入数据
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
*/


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

struct node {
    string name, zw;
    long long bg, dj, id;
} a[200], fbz[2];

struct Node {
    string name;
    long long cnt;
} zw[10];

long long fbzl = 0;

bool cmp(node x, node y) {
    if (x.bg != y.bg)
        return x.bg > y.bg;
    else
        return x.id < y.id;
}

bool cmpp(node x, node y) {
    if (x.dj != y.dj)
        return x.dj > y.dj;
    else
        return x.id < y.id;
}

int main() {
    // freopen("D:/Desktop/11.txt", "r", stdin);
    // freopen("D:/Desktop/1.txt", "w", stdout);

    zw[0].name = "HuFa";
    zw[0].cnt = 2;
    zw[1].name = "ZhangLao";
    zw[1].cnt = 4;
    zw[2].name = "TangZhu";
    zw[2].cnt = 7;
    zw[3].name = "JingYing";
    zw[3].cnt = 25;
    zw[4].name = "BangZhong";
    zw[4].cnt = 100000000;

    long long n;
    cin >> n;
    for (long long i = 0; i < n; i++) {
        cin >> a[i].name >> a[i].zw >> a[i].bg >> a[i].dj;
        a[i].id = i;
        if (a[i].zw == "BangZhu") {
            cout << a[i].name << " " << a[i].zw << " " << a[i].dj << endl;
            i--;
            n--;
        } else if (a[i].zw == "FuBangZhu") {
            fbz[fbzl++] = a[i];
            i--;
            n--;
        }
    }
    if (fbz[0].dj < fbz[1].dj) swap(fbz[0], fbz[1]);
    for (int i = 0; i < 2; i++)
        cout << fbz[i].name << " " << fbz[i].zw << " " << fbz[i].dj << endl;

    // cout << endl;
    sort(a, a + n, cmp);
    for (int i = 0; i < n; i++) cout << a[i].id << " ";
    cout << endl << n << endl;
    long long l = 0, i;
    for (i = 0; i < 3; i++) {
        cout << i << " ";
        if (n - l >= zw[i].cnt) {
            cout << i << " ";
            sort(a + l, a + l + zw[i].cnt, cmpp);
            cout << i << "\n";
            printf("%ld   ", i);
            printf("i:%ld  %ld %ld  i:%ld cnt:%ld\n", i, l, (l + zw[i].cnt), i,
                   zw[i].cnt);
            // for (long long j = l; j < l + zw[i].cnt; j++)
            //     cout << a[j].id << " " << a[j].name << " " << zw[i].name << "
            //     "
            //          << a[j].dj << endl;
            // printf("%ld %ld  i:%ld cnt:%ld\n", l, (l + zw[i].cnt), i,
            //        zw[i].cnt);

            l += zw[i].cnt;
        } else
            break;
    }
    // if (n - l > 0) {
    //     sort(a + l, a + n, cmpp);
    //     for (long long j = l; j < n; j++)
    //         cout << a[j].id << " " << a[j].name << " " << zw[i].name << " "
    //              << a[j].dj << endl;
    // }

    return 0;
}

(少年,这个可不是ac代码,去掉调试也只有30分而已,你要抄的在前面!)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

异想之旅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值