B4414 [GESP202509 三级] 日历制作
B4414 [GESP202509 三级] 日历制作
题目描述
小 A 想制作 202520252025 年每个月的日历。他希望你能编写一个程序,按照格式输出给定月份的日历。
具体来说,第一行需要输出 MON TUE WED THU FRI SAT SUN,分别表示星期一到星期日。接下来若干行中依次输出这个月所包含的日期,日期的个位需要和对应星期几的缩写最后一个字母对齐。例如,202520252025 年 999 月 111 日是星期一,在输出九月的日历时,111 号的个位 111 就需要与星期一 MON 的最后一个字母 N 对齐。九月的日历输出效果如下:
MON TUE WED THU FRI SAT SUN1 2 3 4 5 6 78 9 10 11 12 13 1415 16 17 18 19 20 2122 23 24 25 26 27 2829 30
你能帮助小 A 完成日历的制作吗?
输入格式
一行,一个正整数 mmm,表示需要按照格式输出 202520252025 年 mmm 月的日历。
输出格式
输出包含若干行,表示 202520252025 年 mmm 月的日历。
输入输出样例 #1
输入 #1
9
输出 #1
MON TUE WED THU FRI SAT SUN1 2 3 4 5 6 78 9 10 11 12 13 1415 16 17 18 19 20 2122 23 24 25 26 27 2829 30
输入输出样例 #2
输入 #2
6
输出 #2
MON TUE WED THU FRI SAT SUN12 3 4 5 6 7 89 10 11 12 13 14 1516 17 18 19 20 21 2223 24 25 26 27 28 2930
说明/提示
对于所有测试点,保证 1≤m≤121 \leq m \leq 121≤m≤12。
#include <bits/stdc++.h>
using namespace std;// 每个月的天数(默认平年)
int days_in_month[13] = {0,31, 28, 31, 30, 31, 30,31, 31, 30, 31, 30, 31
};// 星期几的名字
string week[7] = {"MON","TUE","WED","THU","FRI","SAT","SUN"};// 判断闰年
bool isLeap(int year) {return (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
}int main() {int m;cin >> m;int year = 2025;// 如果闰年,2月变成29天if (isLeap(year)) days_in_month[2] = 29;// 2025/1/1 是星期三 (WED)int first_day = 2; // 0=MON,1=TUE,2=WED,...// 累加前几个月的天数,得到m月1日的星期int offset = 0;for (int i = 1; i < m; i++) offset += days_in_month[i];int start_day = (first_day + offset) % 7;// 打印表头for (int i = 0; i < 7; i++) {cout << week[i];if (i < 6) cout << " ";}cout << "\n";// 打印空格(对齐)for (int i = 0; i < start_day; i++) cout << " ";int days = days_in_month[m];for (int d = 1; d <= days; d++) {if(d < 10) cout << " "; else if(d <= 31) cout << " ";cout << d;if((start_day + d) % 7 == 0) cout << "\n";else cout << " ";}cout << "\n";return 0;
}
🧩 一、题目理解
输入一个月份 m
,输出 2025 年该月的日历表(包含星期列和日期排列)。
🧠 二、解题思路总览
1️⃣ 准备数据
- 每个月的天数;
- 星期名称;
- 判断闰年(2 月可能变 29 天)。
2️⃣ 计算该月 1 日是星期几
- 先知道:2025 年 1 月 1 日是星期三;
- 然后累加从 1 月到
m-1
月的天数; - 对 7 取模即可得到该月 1 日的星期。
3️⃣ 打印日历
- 先输出星期标题;
- 根据
start_day
打印空格对齐; - 按顺序打印每一天;
- 每 7 天换一行。
🧱 三、代码结构详细讲解
🧩(1)定义每月天数
int days_in_month[13] = {0,31, 28, 31, 30, 31, 30,31, 31, 30, 31, 30, 31
};
📘 说明:
- 索引从 1 到 12,方便直接用月份访问;
- 默认按照平年天数(2 月 28 天)。
🧩(2)星期名定义
string week[7] = {"MON","TUE","WED","THU","FRI","SAT","SUN"};
📘 用字符串数组存储星期名,方便输出表头。
🧩(3)判断闰年函数
bool isLeap(int year) {return (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
}
📘 标准闰年判断规则:
- 能被 400 整除 → 闰年;
- 能被 4 整除但不能被 100 整除 → 也是闰年;
- 其余情况 → 平年。
🧩(4)主程序部分
int m;
cin >> m;int year = 2025;
读入月份,并设置目标年份。
🧩(5)若闰年则修改 2 月天数
if (isLeap(year)) days_in_month[2] = 29;
2025 年不是闰年,但代码写得通用。
🧩(6)确定已知信息
int first_day = 2; // 2025/1/1 是星期三 -> 对应 week[2]
📘 设定规则:
0=MON, 1=TUE, 2=WED, ...
🧩(7)计算该月 1 日的星期
int offset = 0;
for (int i = 1; i < m; i++) offset += days_in_month[i];
int start_day = (first_day + offset) % 7;
📘 逻辑说明:
offset
是前面几个月的天数总和;- 每过 7 天,星期循环一次;
- 所以
(first_day + offset) % 7
就是目标月 1 日对应的星期。
🧩(8)打印星期表头
for (int i = 0; i < 7; i++) {cout << week[i];if (i < 6) cout << " ";
}
cout << "\n";
📘 输出:
MON TUE WED THU FRI SAT SUN
🧩(9)打印空格对齐(该月第一天前的空位)
for (int i = 0; i < start_day; i++) cout << " ";
📘 每个日期占 4 格(宽度相当),所以空出 start_day
个位置。
🧩(10)循环输出日期
int days = days_in_month[m];
for (int d = 1; d <= days; d++) {if(d < 10) cout << " "; else if(d <= 31) cout << " ";cout << d;if((start_day + d) % 7 == 0) cout << "\n";else cout << " ";
}
cout << "\n";
📘 输出逻辑:
数字前补空格以对齐(个位数字加两个空格);
每 7 天换一行;
通过 (start_day + d) % 7 == 0
判断是否到周日换行。
🧮 四、运行示例
5
输出(2025 年 5 月日历):
MON TUE WED THU FRI SAT SUN1 2 3 45 6 7 8 9 10 1112 13 14 15 16 17 1819 20 21 22 23 24 2526 27 28 29 30 31
🧾 五、程序特点与可改进点
优点 | 改进建议 |
---|---|
✅ 通用性强,可改年份 | 可输入年份 year 而非固定 2025 |
✅ 格式对齐、整齐美观 | 可使用 setw(3) 控制宽度更优雅 |
✅ 模块清晰、逻辑简洁 | 可打印月份标题如 “=== MAY 2025 ===” |
✅ 计算起始星期灵活 | 可扩展为全年日历打印器 |
🧭 程序功能(万年历)
- 用户输入年份与月份(例如
2025 10
) - 程序自动计算该月第一天是星期几
- 1900年1月1日为星期一
#include <bits/stdc++.h>
using namespace std;// 判断闰年
bool isLeap(int year) {return (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
}// 每个月的天数(默认平年)
int days_in_month[13] = {0,31, 28, 31, 30, 31, 30,31, 31, 30, 31, 30, 31
};// 星期几名称
string week[7] = {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};int main() {int year, month;cout << "请输入年份: ";cin >> year;cout << "请输入月份(1-12): ";cin >> month;// 计算从 1900/1/1 到目标年月1号的总天数long long days = 0;// 累加完整年份的天数for (int y = 1900; y < year; y++) {days += isLeap(y) ? 366 : 365;}// 累加本年内前几个月的天数for (int m = 1; m < month; m++) {if (m == 2 && isLeap(year))days += 29;elsedays += days_in_month[m];}// 计算目标年月1日是星期几// 1900/1/1 是 MON -> 余数为 0int start_day = days % 7; // 0=MON,1=TUE,...,6=SUN// 打印标题cout << "\n " << year << "年" << month << "月\n";for (int i = 0; i < 7; i++) {cout << week[i];if (i < 6) cout << " ";}cout << "\n";// 打印前导空格for (int i = 0; i < start_day; i++) cout << " ";int total_days = (month == 2 && isLeap(year)) ? 29 : days_in_month[month];// 打印日期for (int d = 1; d <= total_days; d++) {cout << setw(3) << d << " ";if ((start_day + d) % 7 == 0) cout << "\n";}cout << "\n";return 0;
}
请输入年份: 2025
请输入月份(1-12): 102025年10月
MON TUE WED THU FRI SAT SUN1 2 3 4 56 7 8 9 10 11 1213 14 15 16 17 18 1920 21 22 23 24 25 2627 28 29 30 31
请输入年份: 2000
请输入月份(1-12): 22000年2月
MON TUE WED THU FRI SAT SUN1 2 3 4 5 6 78 9 10 11 12 13 1415 16 17 18 19 20 2122 23 24 25 26 27 2829
请输入年份: 2023
请输入月份(1-12): 22023年2月
MON TUE WED THU FRI SAT SUN1 2 3 4 56 7 8 9 10 11 1213 14 15 16 17 18 1920 21 22 23 24 25 2627 28