1. 程式人生 > >《王道論壇計算機考研機試指南》第二章【經典入門】

《王道論壇計算機考研機試指南》第二章【經典入門】

排序

#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;
}