【问题标题】:Solving USACO 1.1 – Friday the Thirteenth with date.h使用 date.h 解决 USACO 1.1 – 十三号星期五
【发布时间】:2016-06-26 16:16:10
【问题描述】:

USACO 1.1 – Friday the Thirteenth 问题已通过各种方式多次解决。事实上,它通过各种解决方案在 StackOverflow 上产生了一些问题:

问题是:使用modern C++11/14 date library(例如我链接到的那个)的解决方案是什么样的?

它会比其他解决方案简单得多吗?更容易写?效率更高?

【问题讨论】:

  • 一个很好的尝试让一个规范的人尽早解决这些垃圾问题 :-) ...(今天没有投票,抱歉)

标签: c++ date


【解决方案1】:

问题陈述是计算每个月的 13 号在[1900-01-01, 2300-01-01) 范围内的给定工作日的频率。

使用date.h 可以非常轻松高效地完成,如下所示:

#include "date/date.h"
#include <chrono>
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std::chrono;
    unsigned freq[7] = {};
    for (auto ym = 1900_y/January; ym < 2300_y/January; ym += months{1})
        freq[weekday{ym/13}.c_encoding()]++;
    for (unsigned i = 0; i < 7; ++i)
        std::cout << weekday{i} << " : " << freq[i] << '\n';
}

ym 是一个 date::year_month 对象。你可以把它想象成time_point,但它的精度非常粗略,为months

您只需遍历每年和每年的每个月,并计算该月 13 日的星期几,然后将 weekday 转换为 unsigned

高级语法非常简单易读。

底层算法是days_from_civilweekday_from_days。这些低级日期算法都不是迭代的,因此它们非常有效。因此,您可以获得两全其美:可读的高级语法和高性能。

这个简单程序的输出也很可读:

Sun : 687
Mon : 685
Tue : 685
Wed : 687
Thu : 684
Fri : 688
Sat : 684

事实证明,13 号星期五比一周中的其他日子更有可能发生。

在 C++17 中,您甚至可以使用这些结果创建 constexpr std::array&lt;unsigned, 7&gt;(出于某种原因,在编译时拥有这样的数字是否很重要):

#include "date/date.h"
#include <array>
#include <chrono>
#include <iostream>

constexpr
std::array<unsigned, 7>
compute_freq() noexcept
{
    using namespace date;
    using namespace std::chrono;
    decltype(compute_freq()) freq = {};
    for (auto ym = 1900_y/January; ym < 2300_y/January; ym += months{1})
        freq[weekday{ym/13}.c_encoding()]++;
    return freq;
}

constexpr auto freq = compute_freq();

int
main()
{
    using namespace date;
    using namespace std::chrono;
    static_assert(freq[Sunday.c_encoding()]    == 687);
    static_assert(freq[Monday.c_encoding()]    == 685);
    static_assert(freq[Tuesday.c_encoding()]   == 685);
    static_assert(freq[Wednesday.c_encoding()] == 687);
    static_assert(freq[Thursday.c_encoding()]  == 684);
    static_assert(freq[Friday.c_encoding()]    == 688);
    static_assert(freq[Saturday.c_encoding()]  == 684);
}

生成此程序集:

_freq:
    .long   687                     ## 0x2af
    .long   685                     ## 0x2ad
    .long   685                     ## 0x2ad
    .long   687                     ## 0x2af
    .long   684                     ## 0x2ac
    .long   688                     ## 0x2b0
    .long   684                     ## 0x2ac

而且你无法获得比这更高效的方法。

在 C++20 中,这一切都在您的 std::lib 中可用。要将上述程序移植到 C++20,请删除 #include "date/date.h"using namespace date;。还将_y 后缀更改为y

【讨论】:

    猜你喜欢
    • 2015-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多