Skip to content

M27300: 模型整理

sortings, AI, http://cs101.openjudge.cn/pctbook/M27300/

深度学习模型(尤其是大模型)是近两年计算机学术和业界热门的研究方向。每个模型可以用 “模型名称-参数量” 命名,其中参数量的单位会使用两种:M,即百万;B,即十亿。同一个模型通常有多个不同参数的版本。

例如,Bert-110M,Bert-340M 分别代表参数量为 1.1 亿和 3.4 亿的 Bert 模型,GPT3-350M,GPT3-1.3B 和 GPT3-175B 分别代表参数量为 3.5亿,13亿和 1750 亿的 GPT3 模型。

参数量的数字部分取值在 [1, 1000) 区间(一个 8 亿参数的模型表示为 800M 而非 0.8B,10 亿参数的模型表示为 1B 而非 1000M)。

计算机专业的学生小 A 从网上收集了一份模型的列表,他需要将它们按照名称归类排序,并且同一个模型的参数量从小到大排序,生成 “模型名称: 参数量1, 参数量2, ...” 的列表。请你帮他写一个程序实现。

输入

第一行为一个正整数 n(n <= 1000),表示有 n 个待整理的模型。

接下来 n 行,每行一个 “模型名称-参数量” 的字符串。模型名称是字母和数字的混合。

输出

每行一个 “模型名称: 参数量1, 参数量2, ...” 的字符串,符号均为英文符号,模型名称按字典序排列,参数量按从小到大排序。

样例输入

5
GPT-1.3B
Bert-340M
GPT-350M
Bert-110M
GPT-175B

样例输出

Bert: 110M, 340M
GPT: 350M, 1.3B, 175B

提示

tags: string, sort

来源

2023fall zyn

cpp
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;

class Model {
private:
    string raw;       // 原始参数量字符串,比如 "350M" 或 "1.3B"
    double value;     // 换算成 B 的数值,方便比较

public:
    string name;      // 模型名公开

    // 构造函数:接收 "模型名-参数量" 字符串
    Model(const string& fullname) {
        size_t pos = fullname.find('-');
        name = fullname.substr(0, pos);
        raw = fullname.substr(pos + 1);

        char unit = raw.back();
        double num = stod(raw.substr(0, raw.size() - 1));
        if (unit == 'M') {
            value = num / 1000.0;  // 百万 → 十亿
        } else {
            value = num;           // 已经是 B
        }
    }

    // 提供获取原始参数量字符串的方法
    string getRaw() const {
        return raw;
    }

    // 重载 < 运算符用于排序
    bool operator<(const Model& other) const {
        if (name == other.name) {
            return value < other.value;
        }
        return name < other.name;
    }
};

int main() {
    int n;
    cin >> n;
    vector<Model> models;
    models.reserve(n);

    for (int i = 0; i < n; i++) {
        string s;
        cin >> s;
        models.emplace_back(s);
    }

    sort(models.begin(), models.end());

    cout << models[0].name << ": " << models[0].getRaw();
    for (int i = 1; i < n; i++) {
        if (models[i].name == models[i - 1].name) {
            cout << ", " << models[i].getRaw();
        } else {
            cout << "\n" << models[i].name << ": " << models[i].getRaw();
        }
    }
    cout << "\n";

    return 0;
}

reserve → 提前分配内存

emplace_back → 直接构造对象,避免不必要拷贝

struct = 数据结构(默认 public)

class = 面向对象(默认 private)

功能上完全等价,选择哪种主要看语义

  • 你只是存数据 → struct 更清晰
  • 你需要封装/隐藏/继承 → class 更合适

如果用 class

cpp
class Model {
    string name;
    double value;
};
  • 默认是 private
  • 你必须提供 getter 或者把成员改成 public
cpp
class Model {
public:
    string name;
    double value;
};

思路:核心在数据的接收上,排序可以直接sort(),只要数据接收正确就可以,用时约10分钟

cpp
#include <iostream>
#include <sstream>
#include <map>
#include <vector>
#include <algorithm>


using namespace std;

// 把参数量字符串转成数值 (统一为实际参数个数)
long parseParam(const string& s) 
{
    double num = stod(s.substr(0, s.size() - 1));
    char unit = s.back();
    if (unit == 'M') return (long)(num * 1e6 + 0.5);
    if (unit == 'B') return (long)(num * 1e9 + 0.5);
    return 0; 
}

int main() 
{
    int n;
    cin >> n;
    //以模型名称为键,参数量为值
    map<string, vector<pair<long , string>>> models;

    for (int i = 0; i < n; i++) 
    {
        string input;
        cin >> input;

        // 拆分 模型名称 和 参数量
        size_t pos = input.find('-');
        string name = input.substr(0, pos);
        string param = input.substr(pos + 1);

        long value = parseParam(param);
        models[name].push_back({ value, param });
    }

    // 按名称字典序输出
    for (auto& temp : models) 
    {
        string name = temp.first;
        auto& vec = temp.second;

        // 按数值排序
        sort(vec.begin(), vec.end());

        cout << name << ": ";
        for (int i = 0; i < vec.size(); i++) 
        {
            if (i > 0) cout << ", ";
            cout << vec[i].second;
        }
        cout << "\n";
    }

    return 0;
}