《王道論壇計算機考研機試指南》第二章【經典入門】
排序
#include <iostream>
#include <algorithm>
using namespace std;
bool cmp(int x, int y) { // 定義排序規則
return x > y;
}
int main() {
int n;
int buf[100];
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; i++) {
scanf("%d", &buf[i]);
}
sort(buf, buf+n, cmp); // 使用該過載形式,我們表明將要使用自己定義的排列規則
for (int i = 0; i < n; i++) {
printf("%d " , buf[i]);
}
printf("\n");
}
return 0;
}
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct E {
char name[101];
int age;
int score;
} buf[1000];
bool cmp(E a, E b) { // 定義排序規則
if (a.score != b.score) return a.score < b.score; // 若分數不相同則分數低者在前
int tmp = strcmp(a.name, b.name);
if (tmp != 0)
return tmp < 0; // 若分數相同則名字字典序小者在前
else return a.age < b.age; // 若名字也相同則年齡小者在前
}
int main() {
int n;
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; i++) {
scanf("%s%d%d", buf[i].name, &buf[i].age, &buf[i].score);
}
sort(buf, buf+n, cmp); // 使用自己定義的規則排序
for (int i = 0; i < n; i++) {
printf("%s %d %d\n" , buf[i].name, buf[i].age, buf[i].score);
}
}
return 0;
}
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct E {
char name[101];
int age;
int score;
bool operator < (const E& b) const { // 利用C++運算子過載直接定義小於號
if (score != b.score) return score < b.score; // 若分數不相同則分數低者在前
int tmp = strcmp(name, b.name);
if (tmp != 0)
return tmp < 0; // 若分數相同則名字字典序小者在前
else return age < b.age; // 若名字也相同則年齡小者在前
}
} buf[1000];
int main() {
int n;
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; i++) {
scanf("%s%d%d", buf[i].name, &buf[i].age, &buf[i].score);
}
sort(buf, buf+n); // 使用自己定義的規則排序
for (int i = 0; i < n; i++) {
printf("%s %d %d\n" , buf[i].name, buf[i].age, buf[i].score);
}
}
return 0;
}
日期類問題
日期差值
該例題考察了日期類問題中最基本的問題——求兩個日期間的天數差,即求
分別以兩個特定日期為界的日期區間的長度。
這裡值得一提的是,解決這類區間問題有一個統一的思想——把原區間問題統一到起點確定的區間問題上去。在該例中,我們不妨把問題統一到特定日期與一個原點時間(如 0000 年 1 月 1 日)的天數差,當要求兩個特定的日期之間的天數差時,我們只要將它們與原點日期的天數差相減,便能得到這兩個特定日期之間的天數差(必要時加絕對值)。
這樣做有一個巨大的好處——預處理。我們可以在程式真正開始處理輸入資料之
前,預處理出所有日期與原點日期之間的天數差並儲存起來。當資料真正開始輸
入時,我們只需要用 O(1)的時間複雜度將儲存的資料讀出,稍加處理便能得
到答案。值得一提的是,預處理也是空間換時間的重要手段(儲存預處理所得數
據所需的記憶體來換取實時處理所需要的時間消耗)。
另外,日期類問題有一個特別需要注意的要點——閏年,每逢閏年 2 月將會
有 29 天,這對我們計算天數勢必會產生重大的影響。這裡,我們必須明確閏年
的判斷規則——當年數不能被 100 整除時若其能被 4 整除則為閏年,或者其能被
400 整除時也是閏年。用邏輯語言表達出來即為
Year % 100 != 0 && Year % 4 == 0 || Year % 400 == 0
當邏輯表示式為 true 時,其為閏年;反之則不是閏年。
從中我們也可以看出,閏年並不嚴格的按照四年一次的規律出現,在某種情況下也可能出現兩個相鄰閏年相隔八年的情況(如 1896 年與 1904 年)。所以,這裡我們推薦嚴格按照上述表示式來判斷某一年是否是閏年,而不採用某一個閏年後第四年又是閏年的規則。
#include <iostream>
int isYeap(int x) {
if ( (x % 100 != 0 && x % 4 == 0) || x % 400 == 0)
return 1;
return 0;
}
// 預存每月的天數,注意二月定義做特殊處理
int dayOfMonth[13][2] = { 0, 0, 31, 31, 28, 29, 31, 31, 30, 30, 31, 31,
30, 30, 31, 31, 31, 31, 30, 30, 31, 31, 30, 30, 31, 31};
struct Date{ // 日期類,方便日期的推移
int Day;
int Month;
int Year;
void nextDay() {
Day++;
if (Day > dayOfMonth[Month][isYeap(Year)]) { // 若日超過了當月最大日數
Day = 1;
Month++; // 近入下一月
if (Month > 12) {
Month = 1;
Year++; // 進入下一年
}
}
}
};
int buf[5001][13][32]; // 儲存預處理的天數
int Abs(int x) {
return x < 0 ? -x : x;
}
int main() {
Date tmp;
int cnt = 0; // 天數計數
tmp.Day = 1;
tmp.Month = 1;
tmp.Year = 0; // 初始化日期類物件為0年1月1日
while (tmp.Year != 5001) { // 日起不超過5000年
buf[tmp.Year][tmp.Month][tmp.Day] = cnt; // 將該日與0年1月1日的天數差儲存起來
tmp.nextDay(); // 計算下一天日期
cnt++; // 計數器累加,沒經過一天計數器即+1,代表與原點日期的間隔又增加一天
}
int d1, m1, y1, d2, m2, y2;
while (scanf("%4d%2d%2d", &y1, &m1, &d1) != EOF) {
scanf("%4d%2d%2d", &y2, &m2, &d2); // 讀入要計算的兩個日期
printf("%d\n", Abs(buf[y2][m2][d2] - buf[y1][m1][d1]) + 1);
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>
int isYeap(int x) {
if ( (x % 100 != 0 && x % 4 == 0) || x % 400 == 0)
return 1;
return 0;
}
// 預存每月的天數,注意二月定義做特殊處理
int dayOfMonth[13][2] = { 0, 0, 31, 31, 28, 29, 31, 31, 30, 30, 31, 31,
30, 30, 31, 31, 31, 31, 30, 30, 31, 31, 30, 30, 31, 31};
struct Date{ // 日期類,方便日期的推移
int Day;
int Month;
int Year;
void nextDay() {
Day++;
if (Day > dayOfMonth[Month][isYeap(Year)]) { // 若日超過了當月最大日數
Day = 1;
Month++; // 近入下一月
if (Month > 12) {
Month = 1;
Year++; // 進入下一年
}
}
}
};
int buf[3001][13][32]; // 儲存預處理的天數
char monthName[13][20] = {
"", "January", "February", "March", "April", "May", "June", "July", "August",
"September", "October", "November", "December"}; // 月名,每個月名對應下標1到12
// 周名,每個周名對應下標0到6
char weekName[7][20] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
int main() {
Date tmp;
int cnt = 0; // 天數計數
tmp.Day = 1;
tmp.Month = 1;
tmp.Year = 0; // 初始化日期類物件為0年1月1日
while (tmp.Year != 3001) { // 日起不超過3000年
buf[tmp.Year][tmp.Month][tmp.Day] = cnt; // 將該日與0年1月1日的天數差儲存起來
tmp.nextDay(); // 計算下一天日期
cnt++; // 計數器累加,沒經過一天計數器即+1,代表與原點日期的間隔又增加一天
}
int d, m, y;
char s[20];
while (scanf("%d%s%d", &d, s, &y) != EOF) {
for (m = 1; m <= 12; m++) {
if (strcmp(s, monthName[m]) == 0)
break; // 將輸入字串與月名比較得出月數
}
int days = buf[y][m][d] - buf[2018][6][18]; // 計算給定日期與 今日日期的天數間隔(注意可能為負)
days += 1; // 今天2018.6.18為星期一,對應陣列下標為1,則計算1經過days天后的下標
printf("%s", weekName[(days%7+7)%7]); // 將計算後得出的下標用7對其取模,並且保證其為非負數,則該下標即為答案所對應的下標
}
return 0;
}
Hash應用
#include <iostream>
#include <cstring>
using namespace std;
int score[105];
int main() {
int n, s;
while (scanf("%d", &n) != EOF) {
memset(score, 0, sizeof(score));
while (n--) {
cin >> s;
score[s]++;
}
cin >> s;
printf("%d\n", score[s]);
}
return 0;
}
Sort
題目描述:
給你 n 個整數,請按從大到小的順序輸出其中前 m 大的數。
輸入:
每組測試資料有兩行,第一行有兩個數 n,m(0<n,m <1000000),第二行包含 n
個各不相同,且都處於區間[-500000,500000]的整數。
輸出:
對每組測試資料按從大到小的順序輸出前 m 大的數。
樣例輸入:
53
3 -35 92 213 -644
樣例輸出:
213 92 3
#include <iostream>
#include <cstdio>
using namespace std;
const int OFFSET = 500000; // 偏移量,用於補償實際數字與陣列下標之間的偏移
int Hash[1000001]; // Hash陣列,記錄每個數字是否出現,不出現為0,出現後被標記為1
int main() {
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = -500000; i <= 500000; i++) {
Hash[i+OFFSET] = 0; // 初始化,將每個數字都標記為未出現
}
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
Hash[x+OFFSET] = 1; // 凡是出現過的數字,該陣列元素均被設定為1
}
for (int i = 500000; i >= -500000; i--) { // 輸出前m個數
if (Hash[i+OFFSET] == 1) { // 若該數字在輸入中出現
printf("%d", i); // 輸出該數字
m--;
if (m != 0)
printf(" ");
else {
printf("\n");
break;
}
}
}
}
return 0;
}