zoukankan      html  css  js  c++  java
  • 2016-第七届蓝桥杯大赛个人赛省赛(软件类)真题 C大学A组

    返回目录

    题目一览:

    1.网友年龄

    2.生日蜡烛

    3.方格填数

    4.快速排序

    5.消除尾一

    6.寒假作业

    7.剪邮票

    8.四平方和

    9.密码脱落

    10.最大比例

    1.网友年龄

    某君新认识一网友。
    当问及年龄时,他的网友说:
    “我的年龄是个2位数,我比儿子大27岁,
    如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄”

    请你计算:网友的年龄一共有多少种可能情况?

    提示:30岁就是其中一种可能哦.

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

    思路:枚举判断

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 bool check(int x) {
     5     int y = x - 27;
     6     int xx = x%10 * 10 + x/10;
     7     if(xx == y) return true;
     8     return false;
     9 }
    10 
    11 int main() {
    12     int cnt = 0;
    13     for(int i=10; i<=99; ++i)
    14         if(check(i)) {
    15             printf("%d
    ", i); 
    16             cnt ++;
    17         }
    18     cout << cnt << endl;
    19     return 0;
    20 }
    1.网友年龄

    答案:7

    2.生日蜡烛

    某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。

    现在算起来,他一共吹熄了236根蜡烛。

    请问,他从多少岁开始过生日party的?

    请填写他开始过生日party的年龄数。
    注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

    思路:枚举+判断

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 bool flag = true;
     5 int age = 0;
     6 
     7 bool check(int x) {
     8     int sum = 0;
     9     while(sum < 236) { // 这里是< 
    10         sum += x;
    11         x++;
    12     }
    13     if(sum == 236) return true;
    14     else return false;
    15 }
    16 
    17 int main() {
    18     while(flag && age<100) {
    19         age++;
    20         if(check(age))
    21             flag = false;
    22     } 
    23     cout << age << endl;
    24     return 0;
    25 }
    2.生日蜡烛

    答案:26

    3.方格填数

    如下的10个格子
    +--+--+--+
    | | | |
    +--+--+--+--+
    | | | | |
    +--+--+--+--+
    | | | |
    +--+--+--+

    (如果显示有问题,也可以参看【图1.jpg】)

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

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

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

    方法一:将该10个格子按顺序拉成一个一维数组,然后将十个数字填进去(全排列),填完之后进行判断即可。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int a[11], Ans;
     5 
     6 int calc(int x, int y) {
     7     return abs(a[x]-a[y]);
     8 }
     9 
    10 bool check() {
    11     if(calc(0, 1) == 1) return false;
    12     if(calc(0, 3) == 1) return false;
    13     if(calc(0, 4) == 1) return false;
    14     if(calc(0, 5) == 1) return false;
    15     
    16     if(calc(1, 2) == 1) return false;
    17     if(calc(1, 4) == 1) return false;
    18     if(calc(1, 5) == 1) return false;
    19     if(calc(1, 6) == 1) return false;
    20 
    21     if(calc(2, 5) == 1) return false;
    22     if(calc(2, 6) == 1) return false;
    23     
    24     if(calc(3, 4) == 1) return false;
    25     if(calc(3, 7) == 1) return false;
    26     if(calc(3, 8) == 1) return false;
    27     
    28     if(calc(4, 5) == 1) return false;
    29     if(calc(4, 7) == 1) return false;
    30     if(calc(4, 8) == 1) return false;
    31     if(calc(4, 9) == 1) return false;
    32     
    33     if(calc(5, 6) == 1) return false;
    34     if(calc(5, 8) == 1) return false;
    35     if(calc(5, 9) == 1) return false;
    36     
    37     if(calc(6, 9) == 1) return false;
    38     if(calc(7, 8) == 1) return false;
    39     if(calc(8, 9) == 1) return false;
    40     return true;
    41 }
    42 
    43 void dfs(int pos) {
    44     if(pos == 10) {
    45         if(check()) Ans ++;
    46         return ;
    47     }
    48     for(int i=pos; i<10; ++i) {
    49         int t = a[pos]; a[pos] = a[i]; a[i] = t;
    50         dfs(pos+1);
    51         t = a[pos]; a[pos] = a[i]; a[i] = t;
    52     }
    53 }
    54 
    55 int main() {
    56     for(int i=0; i<=10; ++i)
    57         a[i] = i;
    58     dfs(0);
    59     printf("%d
    ", Ans);
    60     return 0;
    61 }
    3.方格填数-方法一

    方法二:在原图的基础上加一圈,然后判断。这个方法的check函数较为简洁。初始化可以不是-10,只要不与0-9相差±1即可。如图:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int Map[5][6], Ans;
     5 bool vis[10];
     6 
     7 bool check(int x, int y) {
     8     for(int i=x-1; i<=x+1; ++i) {
     9         for(int j=y-1; j<=y+1; ++j) {
    10             if(abs(Map[x][y]-Map[i][j]) == 1) 
    11                 return false;  
    12         }
    13     }
    14     return true;
    15 }
    16 
    17 void dfs(int x, int y) {
    18     if(x==3 && y==4) { // 最后一个格子也填了 
    19         Ans++;
    20         return ;
    21     }
    22     for(int i=0; i<10; ++i) {
    23         if(vis[i]) continue; //这个数字用了
    24         Map[x][y] = i; // 先放着 
    25         if(!check(x, y)) {
    26             Map[x][y] = -10; // 
    27             continue; //放下不符规则
    28         }
    29         vis[i] = true;
    30         if(y == 4) 
    31             dfs(x+1, 1); // 换行 
    32         else dfs(x, y+1); // 右边的格子
    33         Map[x][y] = -10; // 回溯 
    34         vis[i] = false; 
    35     }
    36 }
    37 
    38 int main() {
    39     for(int i=0; i<10; ++i) vis[i] = false;
    40     for(int i=0; i<5; ++i) // 外面加一圈 
    41         for(int j=0; j<6; ++j)
    42             Map[i][j] = -10;
    43     dfs(1, 2); //第一个填数的格子是(1,2) 
    44     printf("%d
    ", Ans);
    45     return 0;
    46 }
    3.方格填数-方法二

    答案:1580

    4.快速排序

    排序在各种场合经常被用到。
    快速排序是十分常用的高效率的算法。

    其思想是:先选一个“标尺”,
    用它把整个队列过一遍筛子,
    以保证:其左边的元素都不大于它,其右边的元素都不小于它。

    这样,排序问题就被分割为两个子区间。
    再分别对子区间排序就可以了。

    下面的代码是一种实现,请分析并填写划线部分缺少的代码。

     1 #include <stdio.h>
     2 
     3 void swap(int a[], int i, int j)
     4 {
     5     int t = a[i];
     6     a[i] = a[j];
     7     a[j] = t;
     8 }
     9 
    10 int partition(int a[], int p, int r)
    11 {
    12     int i = p;
    13     int j = r + 1;
    14     int x = a[p];
    15     while(1){
    16         while(i<r && a[++i]<x);
    17         while(a[--j]>x);
    18         if(i>=j) break;
    19         swap(a,i,j);
    20     }
    21     ______________________; // 填空
    22     return j;
    23 }
    24 
    25 void quicksort(int a[], int p, int r)
    26 {
    27     if(p<r){
    28         int q = partition(a,p,r);
    29         quicksort(a,p,q-1);
    30         quicksort(a,q+1,r);
    31     }
    32 }
    33     
    34 int main()
    35 {
    36     int i;
    37     int a[] = {5,13,6,24,2,8,19,27,6,12,1,17};
    38     int N = 12;
    39     
    40     quicksort(a, 0, N-1);
    41     
    42     for(i=0; i<N; i++) printf("%d ", a[i]);
    43     printf("
    ");
    44     
    45     return 0;
    46 }
    4.快速排序

    注意:只填写缺少的内容,不要书写任何题面已有代码或说明性文字。

    思路:我们发现在partition函数中,是以a[p]为标尺,在[p, r]中比a[p]大的和比a[p]小的做交换,那么完成之后就是:a[p],小,小,大,大,大。a[p]显然是要与一个数交换的,那么是i,还是j呢(可以输入i,j输出看一下)。因为我们这个partition函数是要求吧所有小于a[p]的数字放到左边,大于的放到右边,而下标i所指的数是大于a[p]的,与其交换就无法满足要求,所以是与j交换。

    答案:

    swap(a, p, j);

    5.消除尾一

    下面的代码把一个整数的二进制表示的最右边的连续的1全部变成0
    如果最后一位是0,则原数字保持不变。

    如果采用代码中的测试数据,应该输出:

    00000000000000000000000001100111 00000000000000000000000001100000
    00000000000000000000000000001100 00000000000000000000000000001100

    请仔细阅读程序,填写划线部分缺少的代码。

     1 #include <stdio.h>
     2 
     3 void f(int x)
     4 {
     5     int i;
     6     for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
     7     printf("   ");
     8     
     9     x = _______________________; // 填空
    10     
    11     for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
    12     printf("
    ");    
    13 }
    14 
    15 int main()
    16 {
    17     f(103);
    18     f(12);
    19     return 0;
    20 }
    5.消除尾一

    注意:只填写缺少的内容,不要书写任何题面已有代码或说明性文字。

    思路:很显然两个输出是一样的,改变的关键就是我们填空的地方。那就用到了位运算'&'-按位与:如果两个相应的二进制位都为1,则该位的结果值为1,否则为0。看下图

     答案:

    x&(x+1)

    6.寒假作业

    现在小学的数学题目也不是那么好玩的。
    看看这个寒假作业:

    □ + □ = □
    □ - □ = □
    □ × □ = □
    □ ÷ □ = □
    (如果显示不出来,可以参见【图1.jpg】)

    每个方块代表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

    就算两种解法。(加法,乘法交换律后算不同的方案)

    你一共找到了多少种方案?


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

    思路:其实也是全排列问题,把12个格子看成一维数组,然后填充,最后判断。值得注意的是13!很大,直接跑大约需要一分钟左右,这是填空题所以没什么事。但是我们可以添加几个优化。第22行加的语言可以排除很多无用的排列,大大的提高了效率。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int a[13] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
     5 int Ans;
     6 
     7 bool check() {
     8     if(a[9]%a[10] != 0) return false; // 不能整除 
     9     if(a[0]+a[1] != a[2]) return false; // + - * /
    10     if(a[3]-a[4] != a[5]) return false;
    11     if(a[6]*a[7] != a[8]) return false;
    12     if(a[9]/a[10] != a[11]) return false;
    13     return true;
    14 }
    15 
    16 void dfs(int x) {
    17     if(x == 13) { // 填完了 
    18         if(check()) Ans++;
    19     }
    20     for(int i=x; i<13; ++i) { 
    21         swap(a[x], a[i]);
    22         // 剪枝 不满足加法或减法 的跳过
    23         // 因为加减法所需数字在前面 这样就减少了许多无用的 计算 
    24         if((x==2&&a[0]+a[1]!=a[2]) || (x==5&&a[3]-a[4]!=a[5])) {
    25             swap(a[x], a[i]);
    26             continue;
    27         }
    28         dfs(x+1);
    29         swap(a[x], a[i]);
    30     }
    31 }
    32 
    33 int main() {
    34     dfs(0);
    35     cout << Ans << endl;
    36     return 0;
    37 }
    6.寒假作业

    答案:64

    7.剪邮票

    如【图1.jpg】, 有12张连在一起的12生肖的邮票。
    现在你要从中剪下5张来,要求必须是连着的。
    (仅仅连接一个角不算相连)
    比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。

    图1图2

    请你计算,一共有多少种不同的剪取方法。

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

    思路:直接搜索是不大可能的,我们可以把它转变成全排列问题。因为一共12张,需要5张,我们可以创建一个数组,存放5个1和7个0,然后对其进行全排列(这里值得注意的是普通的全排列对重复的数字会产生重复的全排列,简单起见,我们使用c++里面STL中的next_permutation()),然后将其转化成二维数组,然后用dfs搜索看看有几个连通块,只有一个连通块就是一个可行的方案。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int n = 3, m = 4, Map[3][4], Ans;
     5 int a[] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
     6 int u[4] = {-1, 0, 0, 1},
     7     v[4] = {0, -1, 1, 0};
     8 
     9 void dfs(int x, int y) {
    10     Map[x][y] = 0;
    11     for(int i=0; i<4; ++i) {
    12         int xx = x + u[i];
    13         int yy = y + v[i];
    14         if(xx>=0 && xx<3 && yy>=0 && yy<4 && Map[xx][yy]==1)
    15             dfs(xx, yy);
    16     }
    17 }
    18 
    19 bool check() {
    20     for(int i=0; i<3; ++i)
    21         for(int j=0; j<4; ++j)
    22             Map[i][j] = a[4*i+j];
    23     int cnt = 0;
    24     for(int i=0; i<3; ++i)
    25         for(int j=0; j<4; ++j) {
    26             if(Map[i][j] == 1) {
    27                 dfs(i, j);
    28                 cnt++;
    29             }
    30         }
    31     if(cnt == 1) return true;
    32     return false;
    33 }
    34 
    35 void work() { // 利用next_permutation生成不重复的排列 
    36     do {
    37         if(check()) Ans++;
    38     }while(next_permutation(a, a+12));
    39 }
    40 
    41 int main() {
    42     
    43     work();
    44     printf("%d
    ", Ans);
    45     
    46     return 0;
    47 }
    7.剪邮票

    答案:116

    8.四平方和

    四平方和定理,又称为拉格朗日定理:
    每个正整数都可以表示为至多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>, 不能通过工程设置而省略常用头文件。

    提交时,注意选择所期望的编译器类型。

    方法一:由题可知a*a<=N/4,b*b<=N/3,c*c<=N/2,d*d<=N,那么我们就可以四层循环来做,但一个很明显的问题就是会T。然后就是各种神奇的优化,比如说让a*a<=50,b*b<=500。。。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int N;
     5 
     6 int main() {
     7     cin >> N;
     8     for(int a=0; a*a<=50; a++) {
     9         for(int b=a; b*b<=500; b++) {
    10             if(b*b > N) break;
    11             for(int c=b; c*c<=N/2; c++) {
    12                 if(c*c > N) break;
    13                 for(int d=c; d*d<=N; d++) {
    14                     if(d*d > N) break;
    15                     if(a*a+b*b+c*c+d*d == N) {
    16                         printf("%d %d %d %d
    ", a, b, c, d);
    17                         return 0;
    18                     }
    19                 }
    20             }
    21         }
    22     }
    23     return 0;
    24 }
    8.四平方和-方法一

    方法二:我们可以事先处理c*c+d*d,把结果存起来,用map把结果与c或者d形成映射。然后再枚举a、b,用N-a*a-b*b来得到c*c+d*d,判断预处理里面有没有,有的话在N-a*a-b*b-c*c开方求出d即可。

     1 //#include <bits/stdc++.h>
     2 #include <iostream>
     3 #include <map>
     4 #include <cmath>
     5 using namespace std;
     6 
     7 map<int, int> Map;
     8 int N;
     9 
    10 int main() {
    11     scanf("%d", &N);
    12     for(int c=0; c*c<=N/2; ++c)
    13         for(int d=c; c*c+d*d<=N; ++d)
    14             if(Map.find(c*c+d*d) == Map.end())
    15                 Map[c*c+d*d] = c;
    16     for(int a=0; a*a<=N/4; ++a) {
    17         for(int b=a; a*a+b*b<=N/2; ++b) {
    18             if(Map.find(N-a*a-b*b) != Map.end()) {
    19                 int c = Map[N-a*a-b*b];
    20                 int d = (int)sqrt(N-a*a-b*b-c*c);
    21                 printf("%d %d %d %d
    ", a, b, c, d);
    22                 return 0;
    23             }
    24         }
    25     }
    26     return 0;
    27 }
    8.四平方和-方法二

    9.密码脱落

    X星球的考古学家发现了一批古代留下来的密码。
    这些密码是由A、B、C、D 四种植物的种子串成的序列。
    仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。
    由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。

    你的任务是:
    给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。

    输入一行,表示现在看到的密码串(长度不大于1000)
    要求输出一个正整数,表示至少脱落了多少个种子。

    例如,输入:
    ABCBA
    则程序应该输出:
    0

    再例如,输入:
    ABDCDCBABC
    则程序应该输出:
    3

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

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

    注意: main函数需要返回0
    注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
    注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

    提交时,注意选择所期望的编译器类型。

    方法一:爆搜,两端若不相等就分别往左、右添加,代码很简短,但时间复杂度数2^n,是会T的。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 string s;
     5 
     6 int dfs(int l, int r, int cnt) {
     7     if(l >= r) return cnt;
     8     if(s[l] != s[r])
     9         return min(dfs(l+1, r, cnt+1), dfs(l, r-1, cnt+1));
    10     else return dfs(l+1, r-1, cnt);
    11 }
    12 
    13 int main() {
    14     cin >> s;
    15     int Ans = dfs(0, s.length()-1, 0);
    16     printf("%d
    ", Ans);
    17     return 0;
    18 }
    9.密码脱落-方法一-超时

    方法二:要求是对称,那我我们把原串翻转一下,在进行对比可以发现两串有3个不同的字母,那么我们添加这三个字母不就好了。所以答案就是长度-LCS(最长公共子序列)。

     1 #include <bits/stdc++.h>
     2 #include <string>
     3 using namespace std;
     4 
     5 string s, r_s;
     6 int a[1010][1010];
     7 
     8 int LCS() {
     9     int len = s.length();
    10     for(int i=1; i<=len; ++i) {
    11         for(int j=1; j<=len; ++j) {
    12             if(s[i-1] == r_s[j-1])
    13                 a[i][j] = a[i-1][j-1] + 1;
    14             else 
    15                 a[i][j] = max(a[i-1][j], a[i][j-1]);
    16         }
    17     }
    18     return a[len][len];
    19 }
    20 
    21 int main() {
    22     cin >> s;
    23     r_s = s;
    24     reverse(r_s.begin(), r_s.end());
    25     int lcs = LCS();
    26     int Ans = s.length() - lcs;
    27     printf("%d
    ", Ans);
    28     return 0;
    29 }
    9.密码脱落-方法二

    10.最大比例

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

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

    输入格式:
    第一行为数字 N (0<N<100),表示接下的一行包含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

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

    注意: main函数需要返回0
    注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
    注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

    提交时,注意选择所期望的编译器类型。

  • 相关阅读:
    随机ID添加
    学生ID查询
    node.js基础
    冒泡排序
    循环判断语句
    vue.js详细教程--优优优
    final注意事项
    HashMap Hashtable区别
    java中间件
    JSP错误页面
  • 原文地址:https://www.cnblogs.com/Marginalin/p/12603466.html
Copyright © 2011-2022 走看看