《王道论坛计算机考研机试指南》第二章【经典入门】

44 篇文章 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;
}

Day of week

#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;
}
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值