备战考研CCFCSP篇——201503(图像旋转、数字排序、节日、网络延时、最小花费)

试题编号: 201503-1

试题名称: 图像旋转

时间限制: 5.0s

算法类型: 【暴力】

问题描述
  旋转是图像处理的基本操作,在这个问题中,你需要将一个图像逆时针旋转90度。
  计算机中的图像表示可以用一个矩阵来表示,为了旋转一个图像,只需要将对应的矩阵旋转即可。
输入格式
  输入的第一行包含两个整数n, m,分别表示图像矩阵的行数和列数。
  接下来n行每行包含m个整数,表示输入的图像。
输出格式
  输出m行,每行包含n个整数,表示原始矩阵逆时针旋转90度后的矩阵。
样例输入
2 3
1 5 3
3 2 4
样例输出
3 4
5 2
1 3
评测用例规模与约定
  1 ≤ n, m ≤ 1,000,矩阵中的数都是不超过1000的非负整数。

分析:

暴力输出就行,不知道为啥时限那么大…

参考代码

#include<bits/stdc++.h>

using namespace std;

const int maxn = 1e3 + 10;

int mx[maxn][maxn];


int main(){
    int n,m; cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) cin >> mx[i][j];
    }
    for (int i = m; i >= 1; i--) {
        for (int j = 1; j <= n; j++) {
            cout << mx[j][i];
            if (j == n) cout << endl;
            else cout << ' ';
        }
    }

    return 0;
}

试题编号: 201503-2

试题名称: 数字排序

时间限制: 1.0s

算法类型: 【排序】【stl使用】

问题描述
  给定n个整数,请统计出每个整数出现的次数,按出现次数从多到少的顺序输出。
输入格式
  输入的第一行包含一个整数n,表示给定数字的个数。
  第二行包含n个整数,相邻的整数之间用一个空格分隔,表示所给定的整数。
输出格式
  输出多行,每行包含两个整数,分别表示一个给定的整数和它出现的次数。按出现次数递减的顺序输出。如果两个整数出现的次数一样多,则先输出值较小的,然后输出值较大的。
样例输入
12
5 2 3 3 1 3 4 2 5 2 3 5
样例输出
3 4
2 3
5 3
1 1
4 1
评测用例规模与约定
  1 ≤ n ≤ 1000,给出的数都是不超过1000的非负整数。

分析:

水题啊,一万种方法,map记录,利用pair里的内置优先级实现。

参考代码

#include<bits/stdc++.h>

using namespace std;

map<int, int> m;
vector<pair<int,int> > a;


int main(){
    int n; cin >> n;
    for (int i = 0; i < n; i++) {
        int x; cin >>x;
        m[x]++;
    }
    for (auto it : m) {
        a.push_back(make_pair(-it.second, it.first));
    }
    sort(a.begin(), a.end());
    for (int i = 0; i < a.size(); i++) {
        cout << a[i].second << ' ' << -a[i].first << endl;
    }

    return 0;
}

试题编号: 201503-3

试题名称: 节日

时间限制: 1.0s

算法类型:【打表】

问题描述
  有一类节日的日期并不是固定的,而是以“a月的第b个星期c”的形式定下来的,比如说母亲节就定为每年的五月的第二个星期日。
  现在,给你a,b,c和y1, y2(1850 ≤ y1, y2 ≤ 2050),希望你输出从公元y1年到公元y2年间的每年的a月的第b个星期c的日期。
  提示:关于闰年的规则:年份是400的整数倍时是闰年,否则年份是4的倍数并且不是100的倍数时是闰年,其他年份都不是闰年。例如1900年就不是闰年,而2000年是闰年。
  为了方便你推算,已知1850年1月1日是星期二。
输入格式
  输入包含恰好一行,有五个整数a, b, c, y1, y2。其中c=1, 2, ……, 6, 7分别表示星期一、二、……、六、日。
输出格式
  对于y1和y2之间的每一个年份,包括y1和y2,按照年份从小到大的顺序输出一行。
  如果该年的a月第b个星期c确实存在,则以"yyyy/mm/dd"的格式输出,即输出四位数的年份,两位数的月份,两位数的日期,中间用斜杠“/”分隔,位数不足时前补零。
  如果该年的a月第b个星期c并不存在,则输出"none"(不包含双引号)。
样例输入
5 2 7 2014 2015
样例输出
2014/05/11
2015/05/10
评测用例规模与约定
  所有评测用例都满足:1 ≤ a ≤ 12,1 ≤ b ≤ 5,1 ≤ c ≤ 7,1850 ≤ y1, y2 ≤ 2050。

分析:

这题的难度要看从哪个角度入手,我是用了打表的思路,有点坑,从1850年01月01日2050年每一天都预先求出每一天是本月的第几个星期几,然后暴力的查询出 y1 ~ y2年中符合的天数,其中打表这一块有点复杂,详细看看代码吧,过了后,看了看网上的代码,发现自己sb了,可以直接通过天数 映射出星期数,从而可以求出,具体参考这里

参考代码

#include<bits/stdc++.h>
using namespace std;

struct node {
    int y,m,d,cnt,wh;
}a[(int) (1e5 + 10)];

bool isrun(int x) {
    if ((x % 4 == 0 && x % 100 != 0) || x % 400 == 0) return true;
    return false;
}

int run[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
int pin[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int c[8];

void init() {
    a[0].y = 1850;
    a[0].m = 1;a[0].d = 1;a[0].cnt = 1;a[0].wh = 2;
    int l = 1;
    c[2]++;
    while (l < 80000) {
        a[l] = a[l - 1];
        bool pre_r = isrun(a[l - 1].y);
        a[l].d++;
        a[l].wh = a[l - 1].wh == 7 ? 1 : a[l - 1].wh + 1;
        c[a[l].wh]++;
        a[l].cnt = c[a[l].wh];
        if (pre_r) {
            if (a[l].d > run[a[l].m]) {
                memset(c, 0, sizeof c);
                c[a[l].wh]++;
                a[l].cnt = c[a[l].wh];
                a[l].d = 1;
                a[l].m++;
                if (a[l].m == 13) {
                    a[l].m = 1;
                    a[l].y++;
                    memset(c, 0, sizeof c);
                    c[a[l].wh]++;
                    a[l].cnt = c[a[l].wh];
                }
            }
        } else {
            if (a[l].d > pin[a[l].m]) {
                memset(c, 0, sizeof c);
                c[a[l].wh]++;
                a[l].cnt = c[a[l].wh];
                a[l].d = 1;
                a[l].m++;
                if (a[l].m == 13) {
                    memset(c, 0, sizeof c);
                    c[a[l].wh]++;
                    a[l].cnt = c[a[l].wh];
                    a[l].m = 1;
                    a[l].y++;
                }
            }
        }
        l++;
    }
}

int vis[3000];

int main(){
    init();
    int now;
    int x, y, z ,y1,y2; cin >> x >> y >> z >> y1 >> y2;
    now = y1;

    for (int i = 0; i < 80000; i++) {
        if (a[i].y > y2 + 1) break;
        if (a[i].y < y1) continue;
        if (vis[a[i].y]) continue;
        if (a[i].y > now && !vis[now]) {
            puts("none");
            vis[now++] = 1;
        }
        if (now > y2) break;
        if (now == a[i].y && x == a[i].m &&
            y == a[i].cnt && z == a[i].wh) {
            cout << now << "/";
            if (a[i].m < 10) cout << "0" << a[i].m;
            else cout << a[i].m;
            cout << "/";
            if (a[i].d < 10) cout << "0" << a[i].d;
            else cout << a[i].d;
            cout << endl;
            vis[now++] = 1;
        }
    }
    return 0;
}

试题编号: 201503-4

试题名称: 网络延时

时间限制: 1.0s

算法类型: 【多叉树的最大深度】【邻接表】

问题描述
  给定一个公司的网络,由n台交换机和m台终端电脑组成,交换机与交换机、交换机与电脑之间使用网络连接。交换机按层级设置,编号为1的交换机为根交换机,层级为1。其他的交换机都连接到一台比自己上一层的交换机上,其层级为对应交换机的层级加1。所有的终端电脑都直接连接到交换机上。
  当信息在电脑、交换机之间传递时,每一步只能通过自己传递到自己所连接的另一台电脑或交换机。请问,电脑与电脑之间传递消息、或者电脑与交换机之间传递消息、或者交换机与交换机之间传递消息最多需要多少步。
输入格式
  输入的第一行包含两个整数n, m,分别表示交换机的台数和终端电脑的台数。
  第二行包含n - 1个整数,分别表示第2、3、……、n台交换机所连接的比自己上一层的交换机的编号。第i台交换机所连接的上一层的交换机编号一定比自己的编号小。
  第三行包含m个整数,分别表示第1、2、……、m台终端电脑所连接的交换机的编号。
输出格式
  输出一个整数,表示消息传递最多需要的步数。
样例输入
4 2
1 1 3
2 1
样例输出
4
样例说明
  样例的网络连接模式如下,其中圆圈表示交换机,方框表示电脑:
  在这里插入图片描述

其中电脑1与交换机4之间的消息传递花费的时间最长,为4个单位时间。
样例输入
4 4
1 2 2
3 4 4 4
样例输出
4
样例说明
  样例的网络连接模式如下:
在这里插入图片描述
  其中电脑1与电脑4之间的消息传递花费的时间最长,为4个单位时间。
评测用例规模与约定
  前30%的评测用例满足:n ≤ 5, m ≤ 5。
  前50%的评测用例满足:n ≤ 20, m ≤ 20。
  前70%的评测用例满足:n ≤ 100, m ≤ 100。
  所有评测用例都满足:1 ≤ n ≤ 10000,1 ≤ m ≤ 10000。

分析:

首先说下怎么存数据,这题也可以动态的分配内存,利用指针来存,但是有点麻烦(个人觉得),就用了vector邻接表来存了,
根据题意可以知道,如果把交换机和电脑都看成普通节点,本题的答案类似于求多叉树的最大深度,因为所有的计算机一端只能连交换机,所以用一维数组标记哪些交换机有电脑连接即可(这里要注意记录下个数,有坑),
然后再递归求每个交换机节点的深度,这里用了vis数组标记,可以优化时间,然后像求二叉树最大深度类似,遍历完所有的节点,分类讨论即可,如果该节点只有一个孩子节点(注意,这里有坑),应该考虑该节点是否有电脑相连,如果该节点有多个孩子节点,取前两个最大的即可(这里用了优先队列,可以优化时间),

最后说下,这个数据是真有问题呀,有些数据根本没有考虑到,但是也是100分,比如下面的数据
1 1 1
2 1 1 1

有bug代码如下:

#include<bits/stdc++.h>

using namespace std;

const int maxn = 1e4 + 10;

int have[maxn];
vector<int> ch[maxn];

int deap[maxn];
int vis[maxn];

int find_deap(int x) {
    if (vis[x]) return deap[x];
    if (ch[x].size() == 0) {
        if (have[x]) return 1;
        return 0;
    }
    int d = -1;
    for (int i = 0; i < ch[x].size(); i++) {
        d = max(d, find_deap(ch[x][i]));
    }
    vis[x] = 1;
    return deap[x] = d + 1;
}

struct node {
    int t;
    bool operator < (const node &p) const {
        return t < p.t;
    }
};

int main(){
    int n,m; cin >> n >> m;
    for (int i = 2; i <= n; i++) {
        int x; cin >> x;
        ch[x].push_back(i);
    }
    for (int i = 0; i < m; i++) {
        int x; cin >> x; have[x]++;
    }
    for (int i = 1; i <= n; i++) {
        if (vis[i]) continue;
        deap[i] = find_deap(i);
    }
    int res = 0;
    for (int i = 1; i <= n; i++) {
        if (ch[i].size() == 0) continue;
        if (ch[i].size() == 1) {
            if (have[i]) res = max(res, deap[i] + 1);
            else res = max(res, deap[i]);
        }
        else {
            priority_queue<node> p;
            for (int j = 0; j < ch[i].size(); j++) {
                p.push((node){deap[ch[i][j]]});
            }
            int t = p.top().t; p.pop();
            t += p.top().t + 2;
            if (t > res) {
                res = t;
            }
        }
    }
   // if (res == 1 && n + m > 2) res++;
	cout << res << endl;
    return 0;
}

有题可以知道,n,m的最小值都为1,所以答案最少是1,注意下即可

参考代码(无bug):

#include<bits/stdc++.h>

using namespace std;

const int maxn = 1e4 + 10;

int have[maxn];
vector<int> ch[maxn];

int deap[maxn];
int vis[maxn];

int find_deap(int x) {
    if (vis[x]) return deap[x];
    if (ch[x].size() == 0) {
        if (have[x]) return 1;
        return 0;
    }
    int d = -1;
    for (int i = 0; i < ch[x].size(); i++) {
        d = max(d, find_deap(ch[x][i]));
    }
    vis[x] = 1;
    return deap[x] = d + 1;
}

struct node {
    int t;
    bool operator < (const node &p) const {
        return t < p.t;
    }
};

int main(){
    int n,m; cin >> n >> m;
    for (int i = 2; i <= n; i++) {
        int x; cin >> x;
        ch[x].push_back(i);
    }
    for (int i = 0; i < m; i++) {
        int x; cin >> x; have[x]++;
    }
    for (int i = 1; i <= n; i++) {
        if (vis[i]) continue;
        deap[i] = find_deap(i);
    }
    int res = 1;
    for (int i = 1; i <= n; i++) {
        if (ch[i].size() == 0) continue;
        if (ch[i].size() == 1) {
            if (have[i]) res = max(res, deap[i] + 1);
            else res = max(res, deap[i]);
        }
        else {
            priority_queue<node> p;
            for (int j = 0; j < ch[i].size(); j++) {
                p.push((node){deap[ch[i][j]]});
            }
            int t = p.top().t; p.pop();
            t += p.top().t + 2;
            if (t > res) {
                res = t;
            }
        }
    }
   // if (res == 1 && n + m > 2) res++;
	cout << res << endl;
    return 0;
}

第五题是基于点分治的,还没学到,题解在这里,待补

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值