王道機試 第二章 暴力求解
2.2 模擬
2、日期問題
例2.6 今年的第幾天?(清華大學上機複試題)
- 閏年判斷
這裏需要注意的是,閏年的定義是:能被4整除且不能被100整除,或者能被400整除的年份。
#include <iostream>
#include <cstdio>
using namespace std;
int a[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int b[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int f(int y, int m, int d)
{
int sum;
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0){ // 判斷閏年
sum = 0;
for (int i = 0; i < m - 1; i++){
sum += b[i];
}
sum += d;
}
else{
sum = 0;
for (int i = 0; i < m - 1; i++){
sum += a[i];
}
sum += d;
}
return sum;
}
int main()
{
int y, m, d;
while (cin >> y >> m >> d){
cout << f(y, m, d) << endl;
}
return 0;
}
例2.7 打印日期(華中科技大學複試上機題)
- 前導零的輸出——printf方法
C語言可以使用printf的%0md格式在原來數字的基礎上填充前導零,使得其總位數爲m位。 - 其中,m代表輸出的總位數。
- 例如,m=3時,若原來輸出x=22,則使用printf("%03d", x);輸出022
輸出前導0的C代碼如下:
printf("%03d", number); // 輸出number,若number不足3位,則將其高位全部填充爲0.
本題的C++代碼如下:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int a[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int b[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int maxn = 15;
int sa[maxn]; // 前綴和,記錄閏年前k天的總天數
int sb[maxn]; // 前綴和,記錄非閏年前k天的總天數
void solve(int m, int n)
{
if (n <= 31){
printf("%04d-%02d-%02d\n", m, 1, n); return;
}
if ((m % 4 == 0 && m % 100 != 0) || (m % 400 == 0)){ // 判斷閏年
for (int i = 12; i >= 1; i--){
if (n >= sa[i]){
if (n == sa[i]) {printf("%04d-%02d-%02d\n", m, i, a[i - 1]); return;}
else {printf("%04d-%02d-%02d\n", m, i + 1, n - sa[i]); return;}
}
}
}
else{
for (int i = 12; i >= 1; i--){
if (n >= sb[i]){
if (n == sb[i]) {printf("%04d-%02d-%02d\n", m, i, b[i - 1]); return;}
else {printf("%04d-%02d-%02d\n", m, i + 1, n - sb[i]); return;}
}
}
}
}
int main()
{
int m, n;
memset(sa, 0, sizeof(sa));
memset(sb, 0, sizeof(sb));
sa[1] = a[0]; sb[1] = b[0];
for (int i = 2; i <= 12; i++){ // 前綴和,記錄前k個月的總天數
sa[i] = sa[i - 1] + a[i - 1];
sb[i] = sb[i - 1] + b[i - 1];
// cout << sa[i] << " " << sb[i] << endl;
}
while (cin >> m >> n)
{
solve(m, n);
}
return 0;
}
例題2.8 日期累加(北京理工大學複試上機題)
- 坑
日期累加後,年份可能改變!!! - 思路
1、計算總天數
2、判斷總天數是否超出當前年份的天數number_of_year(n)(閏年爲366,非閏年爲365),若超出則減去當前年份的天數,當前年份++,重複步驟2。否則,根據當前的年份,計算該年份中第n天是幾月幾日,並輸出年月日,注意利用printf填充前導零。 - 注意
月份對應天數的數組daytab的每行首個元素均爲0。
C++代碼如下:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
// 坑:日期累加後,年份可能改變!!!
int daytab[][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, // 0
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} // 1
};
bool is_leap_year(int y){ // 是否爲閏年
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) return true;
return false;
}
int number_of_year(int y){ // 每個年份的對應天數
if (is_leap_year(y)) return 366;
else return 365;
}
void solve(int y, int m, int d, int add)
{
int row = is_leap_year(y);
int n = d; // 總天數
for (int j = 1; j <= m - 1; j++){ // 計算當前月份之前的那些月份貢獻的總天數
n += daytab[row][j];
}
n += add; // 計算增加若干天的總天數
while (n > number_of_year(y)){ // 重新計算增加天數後的年份
n -= number_of_year(y);
y++;
}
row = is_leap_year(y); // 判斷更新後的年份是否爲閏年
int month = 1;
while (n > daytab[row][month]){ // 直到小於第month個月份的天數
n -= daytab[row][month];
month++; // 月份+1
}
printf("%04d-%02d-%02d\n", y, month, n);
}
int main()
{
int y, m, d, add;
int t; cin >> t;
while (t--){
cin >> y >> m >> d >> add;
solve(y, m, d, add);
}
return 0;
}
習題2.6 日期差值(上海交通大學複試上機題)
- 說明
本題仍爲日期計算,需要將題目的輸入轉換爲年月日,再進行計算。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
int daytab[][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
bool is_leap_year(int y){
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) return true;
return false;
}
int number_of_year(int y){
if (is_leap_year(y)) return 366;
return 365;
}
void convert(int n, int &y, int &m, int &d){ // 將輸入轉換爲年月日
vector<int> a; a.clear();
int x = n;
while (x){
a.push_back(x % 10);
x /= 10;
}
y = ((a[7]*10 + a[6])*10 + a[5])*10 + a[4];
m = a[3] * 10 + a[2];
d = a[1] * 10 + a[0];
// cout << y << " " << m << " " << d << endl;
}
int days(int y0, int y, int m, int d){ // 以y0年爲基準的天數
int row = is_leap_year(y);
while (y > y0){ // 年
d += number_of_year(y - 1); // 年份之間的天數,從y0到y-1
y--;
}
for (int i = 1; i <= m - 1; i++){ // 月
d += daytab[row][i];
}
return d;
}
int main()
{
int a, b;
int y1, m1, d1;
int y2, m2, d2;
int ans = 1;
while (cin >> a >> b){
if (a < b) swap(a, b); // 默認前者比後者時間長
convert(a, y1, m1, d1);
convert(b, y2, m2, d2);
// cout << y1 << " " << m1 << " " << d1 << endl;
// cout << y2 << " " << m2 << " " << d2 << endl;
int ans1 = days(y2, y1, m1, d1);
int ans2 = days(y2, y2, m2, d2);
// cout << ans1 << " " << ans2 << endl;
ans = ans + ans1 - ans2;
cout << ans << endl; // output
}
return 0;
}
習題2.7 Day of Week
- 思路
1、計算基準年月日1000-01-01是星期幾(利用題目給出的9 October 2001 是星期二對以7位週期倒退)。
2、再計算輸入年月日與其的天數差days,若等於7則星期一致,否則將天數差days對7取模即可。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <string>
using namespace std;
int daytab[][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
map <string, int> month_to_number = {
{"January", 1}, {"February", 2}, {"March", 3}, {"April", 4}, {"May", 5}, {"June", 6},
{"July", 7}, {"August", 8}, {"September", 9}, {"October", 10}, {"November", 11}, {"December", 12}};
map <int, string> number_to_month = {
{1, "Monday"}, {2, "Tuesday"}, {3, "Wednesday"}, {4, "Thursday"},
{5, "Friday"}, {6, "Saturday"}, {7, "Sunday"}};
bool is_leap_year(int y){
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) return true;
return false;
}
int number_of_year(int y){
if (is_leap_year(y)) return 366;
else return 365;
}
int solve(int y, int m, int d){
int row = is_leap_year(y);
while (y > 1000){
y--;
d = d + number_of_year(y);
}
for (int i = 1; i <= m - 1; i++){
d += daytab[row][i];
}
return d - 1;
}
int main()
{
int d, y, m;
string s;
while (cin >> d >> s >> y){
m = month_to_number[s];
int days0 = solve(2001, 10, 9);
int sum = 2; // 從星期二倒退(9 October 2001 是星期二)
while (sum < days0){
sum = sum + 7;
}
sum = sum - days0; // 1000年1月1日的星期
int day = solve(y, m, d);
day = day + 7 - 4;
if (day == 0) cout << number_to_month[sum] << endl; //返回1000年1月1日是星期幾
else if (day % 7 == 0) cout << "Sunday\n";
else cout << number_to_month[(day % 7)] << endl;
}
return 0;
}
習題2.8 日期類(北京理工大學複試上機題)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
// 坑:日期累加後,年份可能改變!!!
int daytab[][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, // 0
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} // 1
};
bool is_leap_year(int y){ // 是否爲閏年
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) return true;
return false;
}
int number_of_year(int y){ // 每個年份的對應天數
if (is_leap_year(y)) return 366;
else return 365;
}
void solve(int y, int m, int d, int add)
{
int row = is_leap_year(y);
int n = d; // 總天數
for (int j = 1; j <= m - 1; j++){ // 計算當前月份之前的那些月份貢獻的總天數
n += daytab[row][j];
}
n += add; // 計算增加若干天的總天數
while (n > number_of_year(y)){ // 重新計算增加天數後的年份
n -= number_of_year(y);
y++;
}
row = is_leap_year(y); // 判斷更新後的年份是否爲閏年
int month = 1;
while (n > daytab[row][month]){ // 直到小於第month個月份的天數
n -= daytab[row][month];
month++; // 月份+1
}
printf("%04d-%02d-%02d\n", y, month, n);
}
int main()
{
int y, m, d, add;
int t; cin >> t;
while (t--){
cin >> y >> m >> d;
int add = 1;
solve(y, m, d, add);
}
return 0;
}