首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在土星附近耗尽燃料

在土星附近耗尽燃料
EN

Code Review用户
提问于 2019-12-15 04:57:01
回答 1查看 168关注 0票数 5

将文件优化/解析为半复杂的数据结构,

效率更高

首先,我想说这段代码是我一直在研究的2019年年代码的出现解决方案的一部分。特别是#14

--第14天:空间计量--当你接近土星环时,你的飞船的低燃料指示器打开了。这里没有任何燃料,但环上有大量的原材料。也许你的船的星际炼油联合品牌纳米工厂可以把这些原材料转化为燃料。您要求纳米工厂生成与此过程相关的反应列表(您的拼图输入)。每一种反应都会将一定数量的特定输入化学物质转化为某种量的输出化学品。几乎每一种化学物质都是由一种反应产生的;唯一的例外是矿石是整个过程的原料输入,而不是由反应产生的。你只需要知道你需要收集多少矿石,才能生产出一单位燃料。每个反应给出其输入和输出的特定数量;反应不能部分运行,因此只能使用这些量的整体整数倍。(不过,当你吃完剩下的化学物质时,还是可以的。)例如,反应1A,2B,3C => 2D意味着完全可以通过消耗1A,2B和3C来产生2个化学单位。你可以在需要的时候多次进行整个反应;例如,你可以通过消耗5A、10B和15C来产生10D。假设你的纳米工厂产生以下一系列反应: 10矿石=> 10A 1 => 1 B 7A,1 B => 1 C 7A,1 C => 1 D 7A,1 D => 1 E 7A,1 E => 1燃料。它们表明,你可以生产你想要的化学A的多少(增加10个单位,每10个成本10矿石)和化学B的多少你想要(每个成本1矿石)。要生产一种燃料,总共需要31颗矿石:1矿石生产1B,然后再生产30多个矿石,以生产7+7+7+7=28A(额外的A浪费2),将B转化为C,C转化为D,D转化为E,最后再将E转化为燃料。(产生30A是因为它的反应要求它以10的增量产生。)或者,假设你有以下的反应清单:9矿石=> 2 A 8矿石=> 3 B 7矿石=> 5 C 3A,4 B => 1 AB 5 B,7 C => 1 BC 4 C,1 A => 1 CA 2 AB,3 BC,4 CA => 1燃料。上述反应需要165个矿石才能生产1种燃料:消耗45矿石来生产10 A。8B生产2 AB.消耗15B,21C生产3 BC.消耗16C,4A生产4 CA.消耗2 AB,3BC 4 CA生产1种燃料。

对于这个特殊问题,我有以下输入格式:

代码语言:javascript
复制
9 ORE => 2 A
8 ORE => 3 B
7 ORE => 5 C
3 A, 4 B => 1 AB
5 B, 7 C => 1 BC
4 C, 1 A => 1 CA
2 AB, 3 BC, 4 CA => 1 FUEL

使用以下方法将其解析到数据结构中:

代码语言:javascript
复制
typedef struct Reagent {
    std::int64_t units;
    std::string chemical;
} Reagent;

using Reactions = std::map<std::string, std::pair<std::int64_t, std::vector<Reagent>>>;

Reactions parse(std::string filename) {
    auto split = [](std::string input) { // Lambda to split each quantity into the reagent struct.
        Reagent reagent;
        std::istringstream parsable(input);
        parsable >> reagent.units >> reagent.chemical;
        return reagent;
    };
    Reactions reactions; // Map to store everything inside.
    std::fstream data(filename);
    std::string line;
    while(std::getline(data, line)) {
        std::vector<Reagent> inputs;
        std::string input, output;
        std::int64_t found;
        if((found = line.find(" => ")) != std::string::npos) { // Split each line into inputs and output by using the ' => '.
            input = line.substr(0, found);
            output = line.substr(found + 4, std::string::npos);
        }
        Reagent result = split(output);
        std::istringstream chemicals(input); // Split the input into a list of reagents.
        std::string str;
        while(std::getline(chemicals, str, ',')) {
            inputs.push_back(split(str));
        }
        reactions.insert({result.chemical, {result.units, inputs}});
    }
    return reactions;
}

我想知道是否有一种更好、更简洁/更聪明的方法来做到这一点,也许标准库中的内容会使它更容易,或者任何简单的代码更改也会变得更容易。

不过,我想保持相同的数据结构。

例如,一个条目当前应该如下所示:

反应“燃料”= {1,试剂载体(AB,BC,CA)}。

谢谢你的建议!

EN

回答 1

Code Review用户

发布于 2019-12-16 13:24:49

快速浏览显示了一些可以改进的东西:

基胡枝子结构试剂

在C++中不需要这样的类型设置,因为我们可以使用structure标记作为类型名。

自动拆分= std::字符串输入 {

也许最好在这里传递一个const std::string&

parsable >> reagent.units >> reagent.chemical;

我希望有一些检查,以确保溪流在之后仍然良好。

在这里有这个split函数是令人惊讶的--我们通常只编写一个operator>>()来流到Reagent对象中。

std::int64\_t found; if((found = line.find(" => "))

这是一个奇怪的类型选择,因为std::string::find()返回一个std::string::size_type,也就是std::size_t:我们应该避免在有符号类型和无符号类型之间进行不必要的转换。

在这种情况下,让编译器确定最合适的类型比较简单:

代码语言:javascript
复制
if (auto found = line.find(" => "); found != std::string::npos)
票数 6
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/234057

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档