srcncpy 和 copy_n 的问题控制字符越界和 std::sort_with_std::find_if

问题描述 投票:0回答:1

编程能力测试(PAT)A1025

由浙江大学计算机科学与技术学院主办。每个测试应该在多个地方同时运行,并且排名列表将在测试后立即合并。现在你的工作是编写一个程序来正确合并所有排名列表并生成最终排名。

输入规格:

每个输入文件包含一个测试用例。对于每种情况,第一行包含一个正数 N (≤100),即测试位置的数量。然后是 N 个排名表,每行开头包含正整数 K(≤300)、考生人数,然后 K 行包含报名号(13 位数字)和每个考生的总成绩。一行中的所有数字均以空格分隔。

输出规格:

对于每个测试用例,首先在一行中打印测试者的总数。然后按以下格式打印最终排名表:

registration_number final_rank location_number local_rank

位置从 1 到 N 编号。输出必须按最终排名的非降序排序。相同分数的考生必须具有相同的排名,并且输出必须按照其注册编号的非降序排列。

示例输入:

2
5
1234567890001 95
1234567890005 100
1234567890003 95
1234567890002 77
1234567890004 85
4
1234567890013 65
1234567890011 25
1234567890014 100
1234567890012 85

示例输出:

9
1234567890005 1 1 1
1234567890014 1 2 1
1234567890001 3 1 2
1234567890003 3 1 2
1234567890004 5 1 4
1234567890012 5 2 2
1234567890002 7 1 5
1234567890013 8 2 3
1234567890011 9 2 4

这是我的:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <cstdio>
struct Student
{
    char id[14];
    int score;
    int r;
    int location = -1;
    int rl;
};
bool cmp(Student a, Student b)
{
    if (a.score != b.score)
        return a.score > b.score;
    else
        return strcmp(a.id, b.id) < 0;
}
int main()
{
    using namespace std;
    int locations = 0;
    int number = 0;
    int n = 0;
    char registration_number[14];
    vector<Student> sumstudents;

    freopen("input.txt", "r", stdin);

    fscanf(stdin, "%d", &locations);  //fscanf返回值需检查
    for (int i = 1; i <= locations; i++)
    {
        vector<Student> students;
        fscanf(stdin, "%d", &n);  
        for (int j = 0; j < n; j++)
        {
            fscanf(stdin, "%13s%d", registration_number, &number);
            if (strlen(registration_number) > 13)
            {
                cerr << "准考证号只有十三位" << endl;
                return 1;
            }
            Student student;
            size_t idlength = strlen(registration_number);
            if (sizeof(student.id) >= idlength + 1)
                copy_n(registration_number, idlength, student.id);
            else
                cout << "数组长度设置有问题";
            student.score = number;
            student.r = 0;
            student.rl = 0;
            student.location = i;
            students.push_back(student);
            registration_number[0] = '\0';
        }
        std::sort(students.begin(), students.end(), cmp);
        students[0].rl = 1;
        sumstudents.push_back(students[0]);
        for (size_t i = 1; i < students.size(); i++)
        {
            if (students[i].score == students[i - 1].score)
            {
                students[i].rl = students[i - 1].rl;
            }
            else
            {
                students[i].rl = i + 1;
            }
            sumstudents.push_back(students[i]);
        }
        students.clear();
        // auto it = find_if(students.begin(), students.end(), [&](const Student &s)
        //                   { return s.location == i; });
        // if (it->location != -1)
        //     it->rl = 1;
        // int flag = 1;
        // while (it != students.end())
        // {
        //     flag++;
        //     auto pre = it;
        //     it = std::find_if(++it, students.end(), [&](const Student &s)
        //                       { return s.location == i; });
        //     if (it->score == pre->score)
        //         it->rl = pre->rl;
        //     else
        //         it->rl = flag;
        // }
    }
    std::sort(sumstudents.begin(), sumstudents.end(), cmp);
    sumstudents[0].r = 1;
    for (size_t i = 1; i < sumstudents.size(); i++)
    {
        if (sumstudents[i].score == sumstudents[i - 1].score)
            sumstudents[i].r = sumstudents[i - 1].r;
        else
            sumstudents[i].r = i + 1;
    }
    cout << sumstudents.size();
    for (Student student : sumstudents)
    {
        cout << '\n'<< student.id << ' ' << student.r << ' ' << student.location << ' ' << student.rl;
    }
    sumstudents.clear();
    return 0;
}

这是其他:

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;

struct Person
{
    // sco: score, fr: final rank
    // ln: location number, lr: local rank
    string id;
    int sco, fr, ln, lr;
};

// compare by score
bool CompSco(Person p1, Person p2)
{
    if (p1.sco == p2.sco)
    {
        return p1.id < p2.id;
    }
    else
    {
        return p1.sco > p2.sco;
    }
}

int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("input.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int N, K, total = 0;
    if (scanf("%d", &N) != 1)
    {

        // 错误处理,例如:打印错误消息,退出程序

        cerr << "Error reading N from input." << endl;

        return 1; // 或者 exit(EXIT_FAILURE);
    }

    vector<Person> pers;
    Person per;
    char id[14];
    // input
    for (int i = 1; i <= N; i++)
    {
        if (scanf("%d", &K) != 1)
        {

            cerr << "Error reading K from input." << endl;

            return 1; // 或者 exit(EXIT_FAILURE);
        }
        vector<Person> tmps; // ** call tmps for simplifying
        for (int j = 0; j < K; j++)
        {
            if (scanf("%s %d", id, &per.sco) != 2)
            {

                cerr << "Error reading ID and/or score from input." << endl;

                return 1; // 或者 exit(EXIT_FAILURE);
            }
            per.id = id;
            per.ln = i;
            per.fr = per.lr = -1;
            tmps.push_back(per);
        }
        // sort local rank
        sort(tmps.begin(), tmps.end(), CompSco);
        tmps[0].lr = 1; //** especially handle zero
        pers.push_back(tmps[0]);
        for (int j = 1; j < K; j++)
        {
            if (tmps[j].sco == tmps[j - 1].sco)
            {
                tmps[j].lr = tmps[j - 1].lr;
            }
            else
            {
                tmps[j].lr = j + 1;
            }
            pers.push_back(tmps[j]);
        }
        total += K;
    }
    // sort final rank
    sort(pers.begin(), pers.end(), CompSco);
    pers[0].fr = 1; // especially handle zero
    for (int k = 1; k < total; k++)
    {
        if (pers[k].sco == pers[k - 1].sco)
        {
            pers[k].fr = pers[k - 1].fr;
        }
        else
        {
            pers[k].fr = k + 1;
        }
    }
    // output
    printf("%d", total);
    for (auto p : pers)
    {
        printf("\n%s %d %d %d", p.id.c_str(), p.fr, p.ln, p.lr);
    }
    return 0;
}

我想知道为什么我的代码是错误的,而另一个是正确的,看起来没有区别

经过一天的努力,发现是copy_n的问题,没有自动在数组末尾添加''。会导致数组越界。在修复这个问题的过程中,我发现使用sort函数全局排序然后使用find_if查找满足条件的对象会大大增加时间复杂度。这是我的最终版本代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
struct Student
{
    char id[14];
    int score;
    int r;
    int location = -1;
    int rl;
};
bool cmp(Student a, Student b)
{
    if (a.score != b.score)
        return a.score > b.score;
    else
        return strcmp(a.id, b.id) < 0;
}
int main()
{
    using namespace std;
    int locations = 0;
    int number = 0;
    int n = 0;
    char registration_number[14];
    vector<Student> allstudents;
    cin >> locations;

    for (int i = 1; i <= locations; i++)
    {
        vector<Student> students;
        cin >> n;
        cin.get();
        for (int j = 0; j < n; j++)
        {
            cin.getline(registration_number, 14, ' ');
            if (cin.fail())
            {
                cerr << "The admission ticket number is only thirteen" << endl;
                return 1;
            }
            if (!(cin >> number))
            {
                cerr << "Error reading the integer." << endl;
                return 1;
            }
            cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
            Student student;
            size_t idlength = strlen(registration_number);
            if (sizeof(student.id) >= idlength + 1)
                strncpy(student.id, registration_number, 14);
            else
                cout << "There is a problem with the array length setting";
            student.score = number;
            student.r = 0;
            student.rl = 0;
            student.location = i;
            students.push_back(student);
        }
        if (students.size() > 0)
        {   
            // The time complexity is greatly increased: sort and find_if
            
            // std::sort(students.begin(), students.end(), cmp);
            // auto it = find_if(students.begin(), students.end(), [&](const Student &s)
            //                   { return s.location == i; });
            // if (it->location != -1)
            //     it->rl = 1;
            // int flag = 1;
            // while (it != students.end())
            // {
            //     flag++;
            //     auto pre = it;
            //     it = std::find_if(++it, students.end(), [&](const Student &s)
            //                       { return s.location == i; });
            //     if (it->score == pre->score)
            //         it->rl = pre->rl;
            //     else
            //         it->rl = flag;
            // }

            sort(students.begin(), students.end(), cmp);
            students[0].rl = 1;
            allstudents.push_back(students[0]);
            for (size_t i = 1; i < students.size(); i++)
            {
                if (students[i].score == students[i - 1].score)
                    students[i].rl = students[i - 1].rl;
                else
                    students[i].rl = i + 1;
                allstudents.push_back(students[i]);
            }
        }
        students.clear();
    }
    if (allstudents.size() > 0)
    {
        sort(allstudents.begin(), allstudents.end(), cmp);
        allstudents[0].r = 1;
        for (size_t i = 1; i < allstudents.size(); i++)
        {
            if (allstudents[i].score == allstudents[i - 1].score)
                allstudents[i].r = allstudents[i - 1].r;
            else
                allstudents[i].r = i + 1;
        }
        cout << allstudents.size();
        for (Student student : allstudents)
        {
            cout << endl
                 << student.id << ' ' << student.r << ' ' << student.location << ' ' << student.rl;
        }
        allstudents.clear();
    }
    return 0;
}
c++ copy std strncpy
1个回答
0
投票

copy_n函数不会插入空字符。一起使用 std::sort 和 std::find_if 会大大增加时间复杂度。

© www.soinside.com 2019 - 2024. All rights reserved.