Viết chương trình tạo lịch trực cho 5 bạn: A, B, C, D, E. Nhập vào năm và tháng cần xếp lịch. Sau đó in lịch trực của tháng đó. Lưu ý: 5 bạn trực lần lượt theo thứ tự trên, ngày Chủ nhật nhật không trực và bạn A sẽ trực ngày đầu tiên của năm.
Ví dụ kết quả chạy chương trình:
2006 5
Sun Mon Tue Wed Thu Fri Sat
1 [C] 2 [D] 3 [E] 4 [A] 5 [B] 6 [C]
7 [ ] 8 [D] 9 [E] 10 [A] 11 [B] 12 [C] 13 [D]
14 [ ] 15 [E] 16 [A] 17 [B] 18 [C] 19 [D] 20 [E]
21 [ ] 22 [A] 23 [B] 24 [C] 25 [D] 26 [E] 27 [A]
28 [ ] 29 [B] 30 [C] 31 [D]
Cách tiếp cận của tôi
Tôi sẽ implement các hàm sau:
- Hàm getDow(day, month, year) tính thứ theo ngày tháng năm dựa vào công thức Zeller cho lịch Gregorian.
- Hàm isLeapYear(year) xác định một năm là năm nhuận hay không.
- Hàm getTop(month, year) trả về số ngày tối đa của một tháng trong năm.
- Hàm getPerson(month, year) trả về người trực đầu tiên của tháng bất kỳ.
Cách implement 3 hàm ở trên, các bạn có thể tham khảo ở đây. Riêng hàm getTop(month, year) thì các bạn có thể xem ở bên dưới.
Coi nhóm bạn như một mảng 5 phần tử {"A", "B", "C", "D", "E"} có index từ 0 tới 4. Tiếp theo tôi sẽ check từng tháng bắt đầu từ tháng 1 cho tới tháng kế cuối. Vì lịch của tôi là lịch bắt đầu từ Chủ Nhật nên với int dow = getDow() = {0, ..., 6} sẽ ứng với {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}. Ví dụ với ngày đầu tiên của tháng 1 năm 2006 là Thứ hai tức int dow = getDow(1, 2006). Chúng ta sẽ dùng một biến index = 0 (tương đương với bạn A). Sau đó quét qua toàn bộ ngày trong tháng. Nếu đó là ngày Chủ Nhật ( (i + dow) % 7 == 0 ) thì index không tăng, ngược lại index tăng 1 đơn vị. Nếu index = 5, tức vượt quá kích thước mảng 5 phần tử ban đầu thì reset index = 0 tức quay về lại bạn A. Sau khi thoát ra khỏi vòng lặp thì lúc này index đang ở vị trí cuối tháng, chỉ cần tăng index lên 1 thì bạn sẽ có index của người đầu tiên phải trực cho tháng kế tiếp.
Bài giải
#include <stdio.h>
int isLeapYear(int y) {
return (!(y % 4) && y % 100) || !(y % 400);
}
int getDow(int q, int m, int y) {
if (m == 1) { m = 13; y--; }
if (m == 2) { m = 14; y--; }
int k = y % 100;
int j = y / 100;
int h = q + (13 * (m + 1)) / 5 + k + k / 4 + j / 4 + 5 * j;
h = h % 7;
return h == 0 ? 6 : h - 1;
}
int getTop(int month, int year) {
int top;
switch(month) {
case 4: case 6: case 9: case 11: top = 30; break;
case 2: top = isLeapYear(year) ? 29 : 28; break;
default: top = 31; break;
}
return top;
}
int getFirstPerson(int month, int year) {
int index = -1;
for (int m = 1; m < month; m++) {
int dow = getDow(1, m, year);
int top = getTop(m, year);
for (int i = 0; i < top; i++) {
if ((i + dow) % 7 != 0) index++;
if (index == 5) index = 0;
}
}
index++;
return index == 5 ? 0 : index;
}
int main() {
char days[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
char student[5][2] = {"A", "B", "C", "D", "E"};
int year, month, cols = 7;
scanf("%d%d", &year, &month);
int dow = getDow(1, month, year);
int top = getTop(month, year);
for (int i = 0; i < cols; i++)
printf("%7s", days[i]);
printf("\n");
for (int i = 0; i < dow; i++) printf("%7s", " ");
int index = getFirstPerson(month, year);
for (int i = 0; i < top; i++) {
(i + dow) % 7 == 0 ? printf("%3d [ ]", i + 1) : printf("%3d [%s]", i + 1, student[index++]);
if (index == 5) index = 0;
if ((i + dow + 1) % cols == 0) printf("\n");
}
return 0;
}