火影 发表于 2025-3-3 22:12:33

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

目录
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 +    —    +——— = 10
       C       GHI
https://i-blog.csdnimg.cn/blog_migrate/e6e74775be41ff179de369c3f02af48c.png
题目解析:
暴力循环,直接用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;
                float b = num * 1.0 / num;
                float c = (num * 100.0 + num * 10 + num) / (num * 100 + num * 10 + num);
                if (fabs(a + b + c - 10) <= 1e-5)
                {
                        cnt++;
                }
        } while (next_permutation(num, num + 9));
        cout << cnt << endl; // 答案29
        return 0;
} 4D:快速排序(9分代码填空)

   题目描述:
排序在各种场合经常被用到。
快速排序是十分常用的高效率的算法。
其思想是:先选一个“标尺”,
用它把整个队列过一遍筛子,
以包管:其左边的元素都不大于它,其右边的元素都不小于它。
这样,排序问题就被分割为两个子区间。
再分别对子区间排序就可以了。
下面的代码是一种实现,请分析并填写划线部分缺少的代码。
#include <stdio.h>
void swap(int a[], int i, int j)
{
        int t = a;
        a = a;
        a = t;
}
int partition(int a[], int p, int r)
{
        int i = p;
        int j = r + 1;
        int x = a;
        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);
        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 1024

void f(int a[], int k, int m, char b[])
{
        int i,j;
        if(k==N)
        {
                b = 0;
                if(m==0) printf("%s\n",b);
                return;
        }
        for(i=0; i<=a; i++)
        {
                for(j=0; j<i; j++)
                        b = k+'A';
                ______________________; //填空位置
        }
}
int main()
{
        int a = {4,2,2,1,1,3};
        char b;
        f(a,0,M,b);
        return 0;
}题目解析:
        起首明白f函数的参数表表示义,此中k表示队伍编号,m表示还必要多少人,对于这种题,判断出是递归,每举行操作一个队伍,所以递归的时间k+1,而m减少相应的人数。答案:
f(a,k+1,m-j,b)
6F:方格填数(15分填空_全分列)

   题目描述:
如下的10个格子
https://i-blog.csdnimg.cn/blog_migrate/107e40c6810608dcca5346ae3a10bc29.png
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)

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

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或阐明性文字。
题目分析:
根据下标全分列,然后用雷同bfs的方法探测:
https://i-blog.csdnimg.cn/blog_migrate/20619f06cee4f6ab26ee5bc9cd247ac3.png
答案1580
#include<iostream>
#include<algorithm>
using namespace std;
int a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int main()
{
        int res = 0;
        do
        {
                if (abs(a - a) != 1 && abs(a - a) != 1 && abs(a - a) != 1 && abs(a - a) != 1 &&
                        abs(a - a) != 1 && abs(a - a) != 1 && abs(a - a) != 1 && abs(a - a) != 1 &&
                        abs(a - a) != 1 && abs(a - a) != 1 &&
                        abs(a - a) != 1 && abs(a - a) != 1 && abs(a - a) != 1 &&
                        abs(a - a) != 1 && abs(a - a) != 1 && abs(a - a) != 1 && abs(a - a) != 1 &&
                        abs(a - a) != 1 && abs(a - a) != 1 && abs(a - a) != 1 &&
                        abs(a - a) != 1 &&
                        abs(a - a) != 1 &&
                        abs(a - a) != 1)
                        ++res;

        } while (next_permutation(a, a + 10));
        cout << res << endl; // 答案1580
        return 0;
}
7G:剪邮票(19分填空)

   题目描述:
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅毗连一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你盘算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或阐明性文字。
https://i-blog.csdnimg.cn/blog_migrate/5560593e1a63d3d26b4e0507164ed709.png
https://i-blog.csdnimg.cn/blog_migrate/bcb20bf8fd10d03907d3c5446eb7e530.png
题目解析:
暴力dfs,答案116
代码1:
#include <algorithm>
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;

int a = { 0,0,0,0,0,0,0,1,1,1,1,1 };

void dfs(vector<vector<int>>& m, int i, int j) {
    m = 0;
    if (i - 1 >= 0 && m == 1) // 四个方向
      dfs(m, i - 1, j);
    if (i + 1 <= 2 && m == 1)
      dfs(m, i + 1, j);
    if (j - 1 >= 0 && m == 1)
      dfs(m, i, j - 1);
    if (j + 1 <= 3 && m == 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 = arr == 1 ? 1 : 0;
      }
    }
    // 连通性检测,如果连通块的数量为1,则是一种正确的方案
    int count = 0; // 连通块的数量
    for (int i = 0; i < 3; i++)
    {
      for (int j = 0; j < 4; j++)
      {
            if (map == 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;
int e;
bool used;

int find(int x)
{
        if (p != x)
                p = find(p);
        return p;
}

void dfs(int u, int start)
{
        if (u == 5)
        {
                for (int i = 1; i <= 12; ++i)
                {
                        p = i;
                }
                for (int i = 1; i <= 12; ++i)
                {
                        for (int j = 1; j <= 12; ++j)
                        {
                                if (e && used && used)
                                {
                                        p = find(j);
                                }
                        }
                }
                int cnt = 0;
                for (int i = 1; i <= 12; ++i)
                {
                        if (used && p == i)
                        {
                                cnt++;
                        }
                }
                if (cnt == 1)
                        ++ans;
                return;
        }

        for (int i = start; i <= 12; ++i)
        {
                if (!used)
                {
                        used = true;
                        dfs(u + 1, i + 1);
                        used = false;
                }
        }
}

int main()
{
        e = e = 1;
        e = e = e = 1;
        e = e = e = 1;
        e = e = 1;
        e = e = e = 1;
        e = e = e = e = 1;
        e = e = e = e = 1;
        e = e = e = 1;
        e = e = 1;
        e = e = e = 1;
        e = e = e = 1;
        e = e = 1;
        dfs(0, 1);
        cout << ans << endl; // 答案116
        return 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 b = b;这样每次操作一定可以至少让一个瓶子回到它原来的位置。
        每一次都从第一个数开始遍历,如果就不符合条件的数就交换,时间复杂度O(N^2),本题的数据范围是1≤N≤10000,显然是可以过的
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1e4 + 10;
int b;
int main()
{
        int n;
        cin >> n;
        for (int i = 1; i <= n; ++i)
        {
                scanf("%d", &b);
        }
        int cnt = 0;
        for (int i = 1; i <= n; ++i)
        {
                for (int j = 1; j <= n; ++j)
                {
                        if (b != j)
                        {
                                cnt++;
                                int idx = b;
                                b = b];
                                b = idx;
                        }
                }
        }
        cout << cnt << endl;
        return 0;
} 解法二及代码(图论)

        转化成图论的问题,数组的每个位置都可以看成是一个环(由于每一个位置必然指向一个位置,且有一个位置指向它)我们想把环的数量变成n个,也就是每一个位置的“指向”都指向本身。
        那么对于任意一个环,交换他们中的 任意两个“指向” 的位置,其产生的影响必然是裂成两个环。而交换不同环 中的 任意两个“指向”的位置,其产生的影响必然是合并两个环。
        此题既可以转化成:“求输入数组构成环的数量k”,每次交换操作至多可以使环的数量+1,所以,最少交换次数就是:n-k;
        那环的数量怎样求?可以开一个bool数组来记录每个位置是否遍历过。如果找到了一个没有遍历过的位置就阐明找到了一个新的环,cnt++,并且循环这个环并且标记全部位置,直到回到头部的位置。       
根据第一个样例
        1 2 3 4 5
        ↓ ↓ ↓ ↓ ↓
        2 1 3 5 4
第一行是原位置,第二行是题目给出的瓶子编号,根据映射关系可以构成一张图。https://i-blog.csdnimg.cn/blog_migrate/13a44bd15a52a2ea8ff18bb994a55341.png
        可以看出上图中有三个环,那么如果瓶子排好序之后,一定是五个自环的关系。那么怎样移动瓶子和环的关系又是什么呢?如果交换环内的点:
https://i-blog.csdnimg.cn/blog_migrate/8c79dd7d4edc2277f7f0b86d8aca7db7.png
假设交换最上方的环内的点 
https://i-blog.csdnimg.cn/blog_migrate/1f259e0e1c82856d7f650df527823a0e.png
  映射关系
                      从                    变为
                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;
bool st;
int main()
{
        cin >> n;
        for (int i = 1; i <= n; ++i)
                cin >> b;

        int cnt = 0;
        for (int i = 1; i <= n; ++i)
        {
                if (!st)
                {
                        ++cnt;//判环个数
                        for (int j = i; !st; j = b)
                        {
                                st = 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数组如果利用辗转相除法求出的就不会是(3/2)^2,而是3/2.这就是原因,所以得用辗转相减法。这是本题的第三个特点。
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 110;
int n;
LL x; // 存放输入的数字
LL a, b; // 分别表示分子和分母
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; // 读入
        }
        sort(x, x + n); // 排序,方便找到首项
        LL dd = 0;
        int cnt = 0;
        for (int i = 1; i < n; i++)
        {
                if (x != x) // 去重:重复的不计入考虑范围
                {
                        dd = gcd(x, x); // 最大公约数
                        a = x / dd; // a=x/dd
                        b = x / dd;
                        cnt++;
                }
        }
        LL up = a, down = b; //up分子 down分母
        for (int i = 1; i < cnt; i++)//分开求分子分母的指数最大公约数
        {
                up = gcd_sub(up, a);
                down = gcd_sub(down, b);
        }
        cout << up << "/" << down;
        return 0;
} 本篇完。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 2016年蓝桥杯第七届C&C++大学B组真题及代码