2016年蓝桥杯第七届CC++大学B组真题及代码

server/2025/3/4 10:33:35/

目录

1A:煤球数目(3分填空_简单枚举)

2B:生日蜡烛(5分填空_简单枚举)

3C:凑算式(11分填空_全排列)

4D:快速排序(9分代码填空)

5E:抽签(13分代码填空)

6F:方格填数(15分填空_全排列)

7G:剪邮票(19分填空)

8H:四平方和(21分编程)

解析代码(循环)

9I:交换瓶子(23分编程)

解法一及代码(贪心)

解法二及代码(图论)

10J:最大比例(31分编程)

解析代码(数论)


1A:煤球数目(3分填空_简单枚举)

题目描述:

有一堆煤球,堆成三角棱锥形。具体:
第一层放1个,
第二层3个(排列成三角形),
第三层6个(排列成三角形),
第四层10个(排列成三角形),…
如果一共有100层,共有多少个煤球?
请填表示煤球总数目的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

题目分析:简单的循环枚举。答案171700

#include <iostream>
using namespace std;int main()
{int sum = 0, res = 0; // 每一层的总数,和全部层的总数for (int i = 1; i <= 100; ++i){sum += i;res += sum;}cout << res << endl;return 0;
}

2B:生日蜡烛(5分填空_简单枚举)

题目描述:

某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。
现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?
请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

题目解析:

        该题目暴力求出,两层循环,第一层表示从多少岁过生日,第二层表示当前多少岁了。满足条件就打印。答案26

#include <iostream>
using namespace std;int main()
{for (int i = 1; i <= 100; ++i){int res = 0; // 总计吹的总数for (int j = i; j <= 100; ++j) // 从第几岁开始过生日{res += j;if (res == 236)cout << i << endl; // 答案26}}return 0;
}

3C:凑算式(11分填空_全排列)

题目描述:

       B       DEF
A +    —    +  ——— = 10C       GHI

题目解析:

暴力循环,直接用next_permutation()。答案29

#include <iostream>
#include <algorithm>
using namespace std;int main()
{int num[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };int cnt = 0;do{float a = num[0];float b = num[1] * 1.0 / num[2];float c = (num[3] * 100.0 + num[4] * 10 + num[5]) / (num[6] * 100 + num[7] * 10 + num[8]);if (fabs(a + b + c - 10) <= 1e-5){cnt++;}} while (next_permutation(num, num + 9));cout << cnt << endl; // 答案29return 0;
}

4D:快速排序(9分代码填空)

题目描述:

排序在各种场合经常被用到。
快速排序是十分常用的高效率的算法
其思想是:先选一个“标尺”,
用它把整个队列过一遍筛子,
以保证:其左边的元素都不大于它,其右边的元素都不小于它。
这样,排序问题就被分割为两个子区间。
再分别对子区间排序就可以了。
下面的代码是一种实现,请分析并填写划线部分缺少的代码。

#include <stdio.h>
void swap(int a[], int i, int j)
{int t = a[i];a[i] = a[j];a[j] = t;
}
int partition(int a[], int p, int r)
{int i = p;int j = r + 1;int x = a[p];while(1){while(i<r && a[++i]<x);while(a[--j]>x);if(i>=j) break;swap(a,i,j);}______________________;//填空return j;
}
void quicksort(int a[], int p, int r)
{if(p<r){int q = partition(a,p,r);quicksort(a,p,q-1);quicksort(a,q+1,r);}
}int main()
{int i;int a[] = {5,13,6,24,2,8,19,27,6,12,1,17};int N = 12;quicksort(a, 0, N-1);for(i=0; i<N; i++) printf("%d ", a[i]);printf("\n");return 0;
}

题目解析:

        快速排序算法是十大经典算法之一,填空部分的函数是用于切割,表示比当前的数小的放左边,比当前数大的放右边,然后依次对左边和右边进行排序。填空部分就是在分完之后,将当前的数进行交换位置。

答案:

  swap(a,p,j)

5E:抽签(13分代码填空)

题目描述:

X星球要派出一个5人组成的观察团前往W星。
其中:
A国最多可以派出4人。
B国最多可以派出2人。
C国最多可以派出2人。

那么最终派往W星的观察团会有多少种国别的不同组合呢?
下面的程序解决了这个问题。
数组a[] 中既是每个国家可以派出的最多的名额。
程序执行结果为:
DEFFF
CEFFF
CDFFF
CDEFF
CCFFF
CCEFF
CCDFF
CCDEF
BEFFF
BDFFF
BDEFF
BCFFF
BCEFF
BCDFF
BCDEF

(以下省略,总共101行)

#include <stdio.h>
#define N 6
#define M 5
#define BUF 1024void f(int a[], int k, int m, char b[])
{int i,j;if(k==N){ b[M] = 0;if(m==0) printf("%s\n",b);return;}for(i=0; i<=a[k]; i++){for(j=0; j<i; j++) b[M-m+j] = k+'A';______________________; //填空位置}
}
int main()
{int a[N] = {4,2,2,1,1,3};char b[BUF];f(a,0,M,b);return 0;
}

题目解析:

        首先理解f函数的参数表示意义,其中k表示队伍编号,m表示还需要多少人,对于这种题,判断出是递归,每进行操作一个队伍,所以递归的时候k+1,而m减少相应的人数。答案:

f(a,k+1,m-j,b)

6F:方格填数(15分填空_全排列)

题目描述:

如下的10个格子

填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)


一共有多少种可能的填数方案?


请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

题目分析:

根据下标全排列,然后用类似bfs的方法探测:

答案1580

#include<iostream>
#include<algorithm>
using namespace std;
int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int main()
{int res = 0;do{if (abs(a[0] - a[1]) != 1 && abs(a[0] - a[3]) != 1 && abs(a[0] - a[4]) != 1 && abs(a[0] - a[5]) != 1 &&abs(a[1] - a[2]) != 1 && abs(a[1] - a[4]) != 1 && abs(a[1] - a[5]) != 1 && abs(a[1] - a[6]) != 1 &&abs(a[2] - a[5]) != 1 && abs(a[2] - a[6]) != 1 &&abs(a[3] - a[4]) != 1 && abs(a[3] - a[7]) != 1 && abs(a[3] - a[8]) != 1 &&abs(a[4] - a[5]) != 1 && abs(a[4] - a[7]) != 1 && abs(a[4] - a[8]) != 1 && abs(a[4] - a[9]) != 1 &&abs(a[5] - a[6]) != 1 && abs(a[5] - a[8]) != 1 && abs(a[5] - a[9]) != 1 &&abs(a[6] - a[9]) != 1 &&abs(a[7] - a[8]) != 1 &&abs(a[8] - a[9]) != 1)++res;} while (next_permutation(a, a + 10));cout << res << endl; // 答案1580return 0;
}


7G:剪邮票(19分填空)

题目描述:

如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

题目解析:

暴力dfs,答案116

代码1:

#include <algorithm>
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;int a[12] = { 0,0,0,0,0,0,0,1,1,1,1,1 };void dfs(vector<vector<int>>& m, int i, int j) {m[i][j] = 0;if (i - 1 >= 0 && m[i - 1][j] == 1) // 四个方向dfs(m, i - 1, j);if (i + 1 <= 2 && m[i + 1][j] == 1)dfs(m, i + 1, j);if (j - 1 >= 0 && m[i][j - 1] == 1)dfs(m, i, j - 1);if (j + 1 <= 3 && m[i][j + 1] == 1)dfs(m, i, j + 1);
}bool check(int arr[])
{vector<vector<int>> map(3, vector<int>(4)); // 生成a对应的二维矩阵for (int i = 0; i < 3; i++){for (int j = 0; j < 4; j++){map[i][j] = arr[i * 4 + j] == 1 ? 1 : 0;}}// 连通性检测,如果连通块的数量为1,则是一种正确的方案int count = 0; // 连通块的数量for (int i = 0; i < 3; i++){for (int j = 0; j < 4; j++){if (map[i][j] == 1){dfs(map, i, j);count++;}}}return count == 1;
}int main()
{int ans = 0;  // 用a数组产生全排列代表选择5个位置的邮票do{if (check(a)){ans++;}} while (next_permutation(a, a + 12));//全排列函数 cout << ans << endl;//cout << clock() << "ms" << endl;//看看跑了多长时间 return 0;
}

代码2:

#include<iostream>
using namespace std;
const int N = 15;int ans;
int p[N];
int e[N][N];
bool used[N];int find(int x)
{if (p[x] != x)p[x] = find(p[x]);return p[x];
}void dfs(int u, int start)
{if (u == 5){for (int i = 1; i <= 12; ++i){p[i] = i;}for (int i = 1; i <= 12; ++i){for (int j = 1; j <= 12; ++j){if (e[i][j] && used[i] && used[j]){p[find(i)] = find(j);}}}int cnt = 0;for (int i = 1; i <= 12; ++i){if (used[i] && p[i] == i){cnt++;}}if (cnt == 1)++ans;return;}for (int i = start; i <= 12; ++i){if (!used[i]){used[i] = true;dfs(u + 1, i + 1);used[i] = false;}}
}int main()
{e[1][2] = e[1][5] = 1;e[2][1] = e[2][3] = e[2][6] = 1;e[3][2] = e[3][4] = e[3][7] = 1;e[4][3] = e[4][8] = 1;e[5][1] = e[5][6] = e[5][9] = 1;e[6][2] = e[6][5] = e[6][7] = e[6][10] = 1;e[7][3] = e[7][6] = e[7][8] = e[7][11] = 1;e[8][4] = e[8][7] = e[8][12] = 1;e[9][5] = e[9][10] = 1;e[10][6] = e[10][9] = e[10][11] = 1;e[11][7] = e[11][10] = e[11][12] = 1;e[12][8] = e[12][11] = 1;dfs(0, 1);cout << ans << endl; // 答案116return 0;
}

8H:四平方和(21分编程)

题目描述:

四平方和定理,又称为拉格朗日定理:
        每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)

对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法


程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开


例如,输入:
5
则程序应该输出:
0 0 1 2


再例如,输入:
12
则程序应该输出:
0 2 2 2


再例如,输入:
773535
则程序应该输出:
1 1 267 838


资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms


解析代码(循环)

题目分析:

        分析:直接四层循环可能会超时,可以考虑先将两个数能构成的平方和保存在map里面,如果在前两层循环的时候,发现剩下的数并不能由两个数的平方构成,就直接continue跳过~否则就判断第三层循环,然后用sqrt(num - a * a - b * b - c * c)算出最后一个数temp,看它是否为整数,如果是整数就输出。这里三层循环+判断也能过了。哈希甚至过不了民间测试。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>using namespace std;int main()
{int i, j, k, p;int n, m;int o;cin >> n;int flag = 0;for (i = 0; i * i < n; ++i){for (j = 0; j * j < n; ++j){for (k = 0; k * k < n; ++k){m = n - i * i - j * j - k * k;o = sqrt(m);if (o * o == m){flag = 1;break;}}if (flag)break;}if (flag)break;}printf("%d %d %d %d\n", i, j, k, o);return 0;
}

9I:交换瓶子(23分编程)

题目描述:

有N个瓶子,编号 1 ~ N,放在架子上。

比如有5个瓶子:
2 1 3 5 4

要求每次拿起2个瓶子,交换它们的位置。
经过若干次后,使得瓶子的序号为:
1 2 3 4 5

对于这么简单的情况,显然,至少需要交换2次就可以复位。

如果瓶子更多呢?你可以通过编程来解决。

输入格式为两行:
第一行: 一个正整数N(N<10000), 表示瓶子的数目
第二行:N个正整数,用空格分开,表示瓶子目前的排列情况。

输出数据为一行一个正整数,表示至少交换多少次,才能完成排序。

例如,输入:
5
3 1 2 5 4

程序应该输出:
3

再例如,输入:
5
5 4 3 2 1程序应该输出:
2


资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms


解法一及代码(贪心)

        贪心:如果第 i 个位置的数不是 i (假设为x),那么就直接将这个数与第 x 个位置的数相交换:b[x] = x b[i] = b[x];这样每次操作一定可以至少让一个瓶子回到它原本的位置。

        每一次都从第一个数开始遍历,如果就不符合条件的数就交换,时间复杂度O(N^2),本题的数据范围是1≤N≤10000,显然是可以过的

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1e4 + 10;
int b[N];
int main()
{int n;cin >> n;for (int i = 1; i <= n; ++i){scanf("%d", &b[i]);}int cnt = 0;for (int i = 1; i <= n; ++i){for (int j = 1; j <= n; ++j){if (b[j] != j){cnt++;int idx = b[j];b[j] = b[b[j]];b[idx] = idx;}}}cout << cnt << endl;return 0;
}

解法二及代码(图论)

        转化成图论的问题,数组的每个位置都可以看成是一个环(因为每一个位置必然指向一个位置,且有一个位置指向它)我们想把环的数量变成n个,也就是每一个位置的“指向”都指向自己。

        那么对于任意一个环,交换他们中的 任意两个“指向” 的位置,其产生的影响必然是裂成两个环。而交换不同环 中的 任意两个“指向”的位置,其产生的影响必然是合并两个环

        此题既可以转化成:“求输入数组构成环的数量k”,每次交换操作至多可以使环的数量+1,所以,最少交换次数就是:n-k;

        那环的数量如何求?可以开一个bool数组来记录每个位置是否遍历过。如果找到了一个没有遍历过的位置就说明找到了一个新的环,cnt++,并且循环这个环并且标记所有位置,直到回到头部的位置。       

根据第一个样例

        1 2 3 4 5

        ↓ ↓ ↓ ↓ ↓

        2 1 3 5 4

第一行是原位置,第二行是题目给出的瓶子编号,根据映射关系可以构成一张图。

        可以看出上图中有三个环,那么如果瓶子排好序之后,一定是五个自环的关系。那么如何移动瓶子和环的关系又是什么呢?如果交换环内的点:

假设交换最上方的环内的点 

  映射关系

                      从                    变为

                1 2 3 4                1 2 3 4

                2 3 4 1                2 1 4 3

根据映射关系可见只是交换了一个瓶子,一个环变为了两个环,可见每次在环内交换瓶子,是会导致环的数量增加 1 的。

        继续看上图,如果我们上一步撤销操作(再把瓶子交换回去),那么就会从两个环变成一个环,可见在两个环之间交换瓶子,是会导致环的数量减少 1 的。

        假设开始有 k 个环, n 个瓶子, 那么根据第一条推论,就可知只需要每次在环内操作 n - k 次就可以让环数变为 n,即题中所求答案!

        那么我们只需要求出环的数量 k,就可以求出最后的答案,求环的数量只需要遍历一次数组,时间复杂度为O(N)。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 10010;
int n;
int b[N];
bool st[N];
int main()
{cin >> n;for (int i = 1; i <= n; ++i) cin >> b[i];int cnt = 0;for (int i = 1; i <= n; ++i){if (!st[i]){++cnt;//判环个数for (int j = i; !st[j]; j = b[j]){st[j] = true;}}}printf("%d\n", n - cnt);//次数=数组元素总个数-环个数return 0;
}

10J:最大比例(31分编程)

题目描述:

X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。
并且,相邻的两个级别间的比例是个固定值。
也就是说:所有级别的奖金数构成了一个等比数列。比如:
16,24,36,54
其等比值为:3/2

现在,我们随机调查了一些获奖者的奖金数。
请你据此推算可能的最大的等比值。

输入格式:
第一行为数字N,表示接下的一行包含N个正整数
第二行N个正整数Xi(Xi<1 000 000 000 000),用空格分开。每个整数表示调查到的某人的奖金数额

要求输出:
一个形如A/B的分数,要求A、B互质。表示可能的最大比例系数

测试数据保证了输入格式正确,并且最大比例是存在的。

例如,输入:
3
1250 200 32

程序应该输出:
25/4

再例如,输入:
4
3125 32 32 200

程序应该输出:
5/2

再例如,输入:
3
549755813888 524288 2

程序应该输出:
4/1

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms


解析代码(数论)

​        拿到这道题目,就知道要求的是可能的等比数列中最大的比例。而且这个比例是个分数,所以我们的初步想法就是得分别计算我们的分子和分母,这是本体的第一个特点。

        其次,我们将数组排个序之后,求出每个数和数组第一个数的最大公约数,在分别计算我们的分子数组和分母数组,求出公约数这是本题的第二个特点。

        然后,我们可以想一下我们如何去求解出我们的公约数,对于这道题目我们不能仅仅只用辗转相除法,因为此式子是分式,如果运用辗转相除法就会出现错误。例如(3/2)^2,(3/2)^4,(3/2)^6这个相除的q[N]数组如果使用辗转相除法求出的就不会是(3/2)^2,而是3/2.这就是原因,所以得用辗转相减法。这是本题的第三个特点。

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 110;
int n;
LL x[N]; // 存放输入的数字
LL a[N], b[N]; // 分别表示分子和分母
LL gcd(LL a, LL b) // 辗转相除
{return b ? gcd(b, a % b) : a;
}
LL gcd_sub(LL a, LL b) // 更相减损
{if (b > a)swap(a, b);if (b == 1)return a;return gcd_sub(b, a / b);
}
int main()
{cin >> n;for (int i = 0; i < n; i++){cin >> x[i]; // 读入}sort(x, x + n); // 排序,方便找到首项LL dd = 0;int cnt = 0;for (int i = 1; i < n; i++){if (x[i] != x[i - 1]) // 去重:重复的不计入考虑范围{dd = gcd(x[i], x[0]); // 最大公约数a[cnt] = x[i] / dd; // a[1]=x[i]/ddb[cnt] = x[0] / dd;cnt++;}}LL up = a[0], down = b[0]; //up分子 down分母for (int i = 1; i < cnt; i++)//分开求分子分母的指数最大公约数{up = gcd_sub(up, a[i]);down = gcd_sub(down, b[i]);}cout << up << "/" << down;return 0;
}

本篇完。


http://www.ppmy.cn/server/172308.html

相关文章

第十五届蓝桥杯:dfs之数字接龙

#include <iostream> using namespace std; const int N 300; int a[N][N];//存值 int b[N][N];//判断某个点是否出现过 int n,k; string path; int dx[] {-1,-1,0,1,1,1,0,-1}; int dy[] {0,1,1,1,0,-1,-1,-1}; bool dfs(int x,int y,int cur,int pos) {if(pos n*n…

Java—初始多线程

多线程的理解 进程&#xff1a; 进程是程序的基本执行实体 每一个运行的软件都是一个进程 线程&#xff1a; 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中&#xff0c;是进程中的实际运作单位。 简单理解&#xff1a;应用软件中互相独立&#xff0c;可以…

npm ERR! code 128 npm ERR! An unknown git error occurred

【问题描述】 【问题解决】 管理员运行cmd&#xff08;右键window --> 选择终端管理员&#xff09; 执行命令 git config --global url.“https://”.insteadOf ssh://git cd 到项目目录 重新执行npm install 个人原因&#xff0c;这里执行npm install --registryhttps:…

realsenseD455相机录制bag转为TUM数据集

本文参考 文章https://blog.csdn.net/m0_60355964/article/details/129518283?ops_request_misc%257B%2522request%255Fid%2522%253A%252211559cdf09f5ff02d4b1d97f2b0744ee%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id11559cdf09f5ff02d…

贪心算法精品题

1.找钱问题 本题的贪心策略在于我们希望就可能的保留作用大的5元 class Solution { public:bool lemonadeChange(vector<int>& bills) {std::map<int ,int> _map;for(auto ch:bills){if(ch 5) _map[ch];else if(ch 10){if(_map[5] 0) return false;else{_m…

计算机毕业设计SpringBoot+Vue.js手机商城 (源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

深度解析Ant Design Pro 6开发实践

深度解析Ant Design Pro 6全栈开发实践&#xff1a;从架构设计到企业级应用落地 一、Ant Design Pro 6核心特性与生态定位&#xff08;技术架构分析&#xff09; 作为Ant Design生态体系的旗舰级企业应用中台框架&#xff0c;Ant Design Pro 6基于以下技术栈实现突破性升级&am…

【Linux第一弹】Linux基础指令(上)

目录 1.ls指令 1.1 ls使用实例 2.pwd指令 3.cd指令 3.1 cd使用实例 4.touch指令 4.1touch使用实例 5.mkdir指令 5.1mkdir使用实例 6.rmdir指令和rm指令 6.1 rmdir指令使用实例->: 6.2 rm指令使用实例 7.man指令 8.cp指令 8.1 cp 使用实例 9.mv指令 9.1mv使用…