ccf-csp 2015春季真题题解


  1. 图像旋转
    问题描述
      旋转是图像处理的基本操作,在这个问题中,你需要将一个图像逆时针旋转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 <iostream>

using namespace std;

const int MAXN = 1010;
int g[MAXN][MAXN];

int main(){
    int n, m;

    cin >> n >> m;
    for(int i = 0; i < n; i ++)
        for(int j = 0; j < m; j ++)
            cin >> g[i][j];

    for(int i = 0; i < m; i ++){
        for(int j = 0; j < n; j ++){
            cout << g[j][m - i - 1] << " ";
        }
        cout << endl;
    }

    return 0;
}

  1. 数字排序
    问题描述
      给定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的非负整数。

代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int MAXN = 1010;
int cnt[MAXN];
typedef pair<int, int> PII;
PII arr[MAXN];

int main(){
    int n, a, pos = 0;

    cin >> n;
    while(n --){
        cin >> a;
        cnt[a] ++;
    }
    for(int i = 0; i < MAXN; i ++)
        if(cnt[i])
        	//插入键值对,键为数字 值为该数字出现的次数
            arr[pos ++] = {i, cnt[i]};
	//按照出现次数降序排列,若相等,则数值越小的越靠前
    sort(arr, arr + pos, [](const PII &a, const PII &b){
        if(a.second != b.second)
            return a.second > b.second;
        else
            return a.first < b.first;
    });
    for(int i = 0; i < pos; i ++)
        cout << arr[i].first << " " << arr[i].second << endl;

    return 0;
}

  1. 节日
    问题描述
      有一类节日的日期并不是固定的,而是以“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。
    题解:
      按照天来模拟,当遍历到公元y1年到公元y2年间的每年的a月的星期c时,使用vector记录每个星期c出现的日期,最后判断vector的大小是否大于等于b,若大于等于b代表这个月有b次星期c,输出相应的日期,否则输出none,代表这个月没有b个星期c 。

代码:

#include <iostream>
#include <vector>

using namespace std;
//每个月份有几天
int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//判断闰年
bool isLeap(int year){
    return (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
}

int main(){
    int t = 0;
    int a, b, c, y1, y2;

    cin >> a >> b >> c >> y1 >> y2;
    c -= 1;

    for(int i = 1850; i <= y2; i ++){
        for(int j = 1; j <= 12; j ++){
            vector<int> g;
            int cnt = days[j];
            //闰年的2月份有29天
            if(j == 2 && isLeap(i))
                cnt = 29;
            for(int k = 1; k <= cnt; k ++){
            	//模拟星期几
                t = (t + 1) % 7;
                //是星期c则加到vector中
                if(t == c)
                    g.push_back(k);
            }
            if(i >= y1 && i <= y2 && j == a){
                if(g.size() < b)
                    printf("none\n");
                else
                    printf("%04d/%02d/%02d\n", i, j, g[b - 1]);
            }
        }
    }

    return 0;
}

  1. 网络延时
    问题描述
      给定一个公司的网络,由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。
    题解:
      题意就是要求出树中任意两个节点间的最大距离(树的直径),模板题。

代码:

#include <iostream>

using namespace std;

const int MAXN = 2 * 10010;
//使用数组来模拟树
int head[MAXN], ver[MAXN], nxt[MAXN], cnt = 1, ans = 0;

void add(int a, int b){
    ver[++ cnt] = b;
    nxt[cnt] = head[a];
    head[a] = cnt;
}

int dfs(int root){
    if(root == 0)
        return 0;
	//a为子树中最大距离,b为子树中次大距离
    int a = 0, b = 0;
    for(int i = head[root]; i; i = nxt[i]){
        int t = dfs(ver[i]);
        if(t > a)
            b = a, a = t;
        else if(t > b)
            b = t;
    }
    //更新ans, 为 a + b
    ans = max(ans, a + b);
    //当前分支最大距离为最大值 a + 1
    return a + 1;
}

int main(){
    int n, m, a;

    cin >> n >> m;
    for(int i = 2; i <= n + m; i ++){
        cin >> a;
        add(a, i);
    }
    dfs(1);
    cout << ans << endl;
    return 0;
}

  1. 最小花费
    问题描述
      C国共有n个城市。有n-1条双向道路,每条道路连接两个城市,任意两个城市之间能互相到达。小R来到C国旅行,他共规划了m条旅行的路线,第i条旅行路线的起点是si,终点是ti。在旅行过程中,小R每行走一单位长度的路需要吃一单位的食物。C国的食物只能在各个城市中买到,而且不同城市的食物价格可能不同。
      然而,小R不希望在旅行中为了购买较低价的粮食而绕远路,因此他总会选择最近的路走。现在,请你计算小R规划的每条旅行路线的最小花费是多少。
    输入格式
      第一行包含2个整数n和m。
      第二行包含n个整数。第i个整数wi表示城市i的食物价格。
      接下来n-1行,每行包括3个整数u, v, e,表示城市u和城市v之间有一条长为e的双向道路。
      接下来m行,每行包含2个整数si和ti,分别表示一条旅行路线的起点和终点。
    输出格式
      输出m行,分别代表每一条旅行方案的最小花费。
    样例输入
    6 4
    1 7 3 2 5 6
    1 2 4
    1 3 5
    2 4 1
    3 5 2
    3 6 1
    2 5
    4 6
    6 4
    5 6
    样例输出
    35
    16
    26
    13
    样例说明
      对于第一条路线,小R会经过2->1->3->5。其中在城市2处以7的价格购买4单位粮食,到城市1时全部吃完,并用1的价格购买7单位粮食,然后到达终点。
    评测用例规模与约定
      前10%的评测用例满足:n, m ≤ 20, wi ≤ 20;
      前30%的评测用例满足:n, m ≤ 200;
      另有40%的评测用例满足:一个城市至多与其它两个城市相连。
      所有评测用例都满足:1 ≤ n, m ≤ 105,1 ≤ wi ≤ 106,1 ≤ e ≤ 10000。
    题解:
      一道巨难的题目,不会hhh。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值