蓝桥杯第七届 省赛 c语言A组
第一题
网友年龄
某君新认识一网友。
当问及年龄时,他的网友说:
“我的年龄是个2位数,我比儿子大27岁,
如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄”
请你计算:网友的年龄一共有多少种可能情况?
提示:30岁就是其中一种可能哦.
请填写表示可能情况的种数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【思路】
写一个循环即可解决问题。
答案:7
#include <iostream>
using namespace std;
int main() {
int rec = 0, note;
for (int i = 1; i <= 99; i++) {
note = (i%10)*10 + i/10;
if (i - note == 27)
rec++;
}
cout << rec << endl;
return 0;
}
第二题
生日蜡烛
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。
现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?
请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【思路】
由于是填空题,用了两个简单的循环。
答案:26
#include <iostream>
using namespace std;
int main() {
int rec, t;
for (int i = 1; i <= 100; i++) {
rec = 0;
t = i;
while (rec < 236) {
rec += t;
t++;
}
if (rec == 236) {
cout << i << endl;
break;
}
}
return 0;
}
第三题
方格填数
如下的10个格子
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)
一共有多少种可能的填数方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【思路】
把所有的情况枚举一遍,把不连续的要求全部列出来,同时满足则找到一种方案。
答案:1580
#include <iostream>
#include <string>
#include <cstdlib>
#include <algorithm>
using namespace std;
bool cn(string s) {
if (abs(s[0]-s[1]) != 1 && abs(s[0]-s[3]) != 1 && abs(s[0]-s[4]) != 1 && abs(s[0]-s[5]) != 1 &&
abs(s[1]-s[2]) != 1 && abs(s[1]-s[4]) != 1 && abs(s[1]-s[5]) != 1 && abs(s[1]-s[6]) != 1 &&
abs(s[2]-s[5]) != 1 && abs(s[2]-s[6]) != 1 &&
abs(s[3]-s[4]) != 1 && abs(s[3]-s[7]) != 1 && abs(s[3]-s[8]) != 1 &&
abs(s[4]-s[5]) != 1 && abs(s[4]-s[7]) != 1 && abs(s[4]-s[8]) != 1 && abs(s[4]-s[9]) != 1 &&
abs(s[5]-s[6]) != 1 && abs(s[5]-s[8]) != 1 && abs(s[5]-s[9]) != 1 &&
abs(s[6]-s[9]) != 1 && abs(s[7]-s[8]) != 1 && abs(s[8]-s[9]) != 1)
return true;
else
return false;
}
int main() {
string s = "0123456789";
int rec = 0;
do {
if (cn(s)) rec++;
} while (next_permutation(s.begin(), s.end()));
cout << rec << endl;
return 0;
}
第四题
快速排序
排序在各种场合经常被用到。
快速排序是十分常用的高效率的算法。
其思想是:先选一个“标尺”,
用它把整个队列过一遍筛子,
以保证:其左边的元素都不大于它,其右边的元素都不小于它。
这样,排序问题就被分割为两个子区间。
再分别对子区间排序就可以了。
下面的代码是一种实现,请分析并填写划线部分缺少的代码。
#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;
}
注意:只填写缺少的内容,不要书写任何题面已有代码或说明性文字。
【思路】
了解快排的同学应该清楚,最终的目标是将"标尺"放到适当的位置,由于这个程序选择的"标尺"在排序的左边,所以应该拿"标尺"与小于"标尺"的最右边的元素交换。
答案:swqp(a,p,j)
第五题
消除尾一
下面的代码把一个整数的二进制表示的最右边的连续的1全部变成0
如果最后一位是0,则原数字保持不变。
如果采用代码中的测试数据,应该输出:
00000000000000000000000001100111 00000000000000000000000001100000
00000000000000000000000000001100 00000000000000000000000000001100
请仔细阅读程序,填写划线部分缺少的代码。
#include <stdio.h>
void f(int x)
{
int i;
for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
printf(" ");
x = ___________;
for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
printf("\n");
}
int main()
{
f(103);
f(12);
return 0;
}
注意:只填写缺少的内容,不要书写任何题面已有代码或说明性文字。
【思路】
一个二进制数,加1,末位连续的1全为0,进位加1,再与原来的数进行与操作,得到结果。
答案:x&(x+1)
第六题
寒假作业
现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:
□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □
每个方块代表1~13中的某一个数字,但不能重复。
比如:
6 + 7 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
以及:
7 + 6 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
就算两种解法。(加法,乘法交换律后算不同的方案)
你一共找到了多少种方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【思路】
深搜+剪枝,别人的思路,剪枝剪得很妙,赞一个!(又学到东西了,开心。)
答案:64
#include <iostream>
#include <cstring>
using namespace std;
int visit[13], a[12];
int rec = 0;
void dfs(int t) {
if (t >= 3 && a[0] + a[1] != a[2]) //剪枝
return ;
if (t >= 6 && a[3] - a[4] != a[5])
return ;
if (t >= 9 && a[6] * a[7] != a[8])
return ;
if (t >= 12 && a[9] == a[10] * a[11]) {
rec++;
return ;
}
if (t >= 12)
return;
for (int i = 1; i <= 13; i++) {
if (!visit[i]) {
visit[i] = 1;
a[t] = i;
dfs(t+1);
visit[i] = 0;
}
}
}
int main() {
memset(a, 0, sizeof(a));
memset(visit, 0, sizeof(visit));
dfs(0);
cout << rec << endl;
return 0;
}
第七题
剪邮票
如
有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,
中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【思路】
参考别人的思路。
1.遍历所有的方案
2.每个方案利用深搜判断是否链接,链接则方案数加一
重点在于深搜的设计。
首先存储到某个方案,调用深搜,dfs()函数遍历到某个点,判断它周围的四个点是否在方案里面,如果在方案里面,且该点未曾被遍历到,则标记该点被遍历。
可以利用每个点的数值得到周围的四个点,但由于4和5不相连,8和9不相连,改变方格的值为:
1 2 3 4
6 7 8 9
11 12 13 14
这样,每个点遍历上下左右的点的距离分别为{-5,+5,-1,+1}
纤细设计兄弟们去体会下代码吧。。。我尽力了。
#include <iostream>
#include <cstring>
using namespace std;
const int num = 5;
int a[num], visit[num], t;
int map[] = {1,2,3,4,6,7,8,9,11,12,13,14};
int b[] = {-1, 1, -5, 5};
void dfs(int n) {
for (int i = 0; i < 4; i++) { //尝试当前点的四个方向
t = a[n] + b[i];
if (t == 5 || t == 10 || t > 14 || t < 1) //t的值不在表格内,遍历下一个方向
continue;
for (int j = 0; j < 5; j++)
if (!visit[j] && t == a[j]) { //当前点的某一个方向的点在当前方案中
visit[j] = 1;
dfs(j);
}
}
}
int main(){
bool flag;
int rec = 0;
for (int i = 0; i < 12; i++)
for (int j = i + 1; j < 12; j++)
for (int k = j + 1; k < 12; k++)
for (int l = k + 1; l < 12; l++)
for (int n = l + 1; n < 12; n++) {
a[0] = map[i];
a[1] = map[j];
a[2] = map[k];
a[3] = map[l];
a[4] = map[n];
memset(visit, 0, sizeof(visit));
dfs(0);
flag = true;
for (int m = 0; m < num; m++)
if (!visit[m]) {
flag = false;
break;
}
if (flag == true)
rec ++;
}
cout << rec << endl;
return 0;
}
第八题
四平方和
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多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
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
【思路】
暴力破解,枚举4个数,符合条件结束程序,用三个循环即可,第四个数直接计算出来,降低时间复杂度。
#include <iostream>
#include <cmath>
using namespace std;
const int NUM = 5000000;
int main(){
int num = sqrt(5000000);
int n, d;
bool flag = false;
cin >> n;
for (int a = 0; a <= num; a++)
for (int b = 0; b <= num; b++)
for (int c = 0; c <= num; c++) {
d = sqrt(n - (a * a + b * b + c * c));
if (n == a * a + b * b + c * c + d * d) {
if (c > d) {
int temp = c;
c = d;
d = temp;
}
cout << a << ' ' << b << ' ' << c << ' ' << d << endl;
return 0;
}
}
}
这里呈上别人的思路。用一个数组存储所有小于n的数中能被2个数的平方和求得的数。从这些数中找出符合条件的数即可,具体实现看代码。这种方法有效地减低了时间复杂度,但是需要消耗更多的内存。
#include <iostream>
#include <cmath>
using namespace std;
const int NUM = 5000010;
int map[NUM] = {0};
int n;
void f() {
for (int i = 0; i * i <= n; i++)
for (int j = 0; j * j <= n; j++)
if (i * i + j * j <= n)
map[i * i + j * j] = 1; //这个数可以用两个数平方求得
}
int main(){
cin >> n;
f();
for (int i = 0; i * i <= n; i++) {
for (int j = 0; j * j <= n; j++) {
if (map[n - i * i - j * j] == 0)
continue;
for (int k = 0; k * k <= n; k++) {
int p = sqrt(n - i * i - j * j - k * k);
if ((i * i + j * j + k * k + p * p) == n) {
cout << i << ' ' << j << ' ' << k << ' ' << p << endl;
return 0;
}
}
}
}
}
第九题
密码脱落
X星球的考古学家发现了一批古代留下来的密码。
这些密码是由A、B、C、D 四种植物的种子串成的序列。
仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。
由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。
你的任务是:
给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。
输入一行,表示现在看到的密码串(长度不大于1000)
要求输出一个正整数,表示至少脱落了多少个种子。
例如,输入:
ABCBA
则程序应该输出:
0
再例如,输入:
ABDCDCBABC
则程序应该输出:
3
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
【思路】
很惭愧还是大神的思路,源博主找不到了,因为看的博客没有标明,学习一下。
用的方法还是我们熟悉的深搜,但是我觉得需要在充分了解题目的基础上,才能知道用这样的判断可以得到答案。。。
#include <iostream>
#include <string>
using namespace std;
int num = 100000;
string str;
void dfs(int l, int r, int len) {
if (l >= r)
num = (num < len ? num : len);
else {
if (str[l] == str[r])
dfs(l + 1, r - 1, len);
else {
dfs(l + 1, r, len + 1);
dfs(l, r - 1, len + 1);
}
}
return ;
}
int main(){
cin >> str;
dfs(0, str.size() - 1, 0);
cout << num << endl;
return 0;
}