USACO 1.1 – Friday the Thirteenth问题已经以各种方式多次解决。实际上,它已经通过各种解决方案在StackOverflow上产生了一些问题:
问题是:使用modern C++11/14 date library这样的解决方案会是什么样的解决方案?
它会比其他解决方案简单得多吗?更容易写?效率更高?
答案 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';
}
ym
是date::year_month
个对象。您可以将其视为time_point
,但它具有非常粗略的months
精度。
您只需循环遍历每年和每年的每个月,并计算当月13日的星期几,并将weekday
投射到unsigned
。
高级语法非常简单易读。
引擎下的算法是days_from_civil
和weekday_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
而你却无法提高效率。