解决USACO 1.1 - 星期五,第13天与date.h

时间:2016-06-26 16:16:10

标签: c++ date

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

问题是:使用modern C++11/14 date library这样的解决方案会是什么样的解决方案?

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

1 个答案:

答案 0 :(得分:6)

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

使用date.h可以非常轻松有效地实现这一目标:

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

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

ymdate::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 ++ 1z(我们希望是C ++ 17)中,您甚至可以使用这些结果创建constexpr std::array<unsigned, 7>(由于某些原因,在编译时使用这些数字是否重要) :

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

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

constexpr auto freq = compute_freq();

int
main()
{
    using namespace date::literals;
    static_assert(freq[unsigned{sun}] == 687);
    static_assert(freq[unsigned{mon}] == 685);
    static_assert(freq[unsigned{tue}] == 685);
    static_assert(freq[unsigned{wed}] == 687);
    static_assert(freq[unsigned{thu}] == 684);
    static_assert(freq[unsigned{fri}] == 688);
    static_assert(freq[unsigned{sat}] == 684);
}

生成此程序集:

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

而你却无法提高效率。