第七届蓝桥杯(2016)-省赛题解_C/C++__大学A组

感悟总结

这年的题总体感觉不难,只有三道编程大题,但一定要细心。
比如第一题,网友年龄,只要个数,第二题只要第一次开party的年龄。
dfs的题明显较多,第三题,第七题,第八题都可以用dfs来做
但第三题和第六题用实际上用全排列的套路更方便!第八题也需要用到全排列!

一、网友年龄(填空题)

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

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

提示:30岁就是其中一种可能哦. 请填写表示可能情况的种数。

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

问的是个数,一定要认真看题,一共有七种(代码显示的再加上题目的30岁)
下面的代码是从1开始枚举的,因为除了30不存在其他0的可能性!

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a,b;
    for(int i=1;i<=9;i++)
        for(int j=1;j<=9;j++){
            int father=i*10+j;
            int son=i+j*10;
            if(father-son==27)
                printf("%d\n",father);
        }
    return 0;
}//41 52 63 74 85 96
二、生日蜡烛(填空题)

某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。 现在算起来,他一共吹熄了236根蜡烛。

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

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

两次for循环,一般年龄在50岁范围内就能找到答案,注意题目只要第一个结果,答案为26!

#include<bits/stdc++.h>
using namespace std;
int main(){
    int sum;
    for(int i=1;i<=50;i++){
        for(int j=i;j<=50;j++){
            sum+=j;
            if(sum==236){
                printf("%d %d",i,j);
                break;
            }
        }
        sum=0;
    }
    return 0;
}//运行结果26 33
三、方格填数(填空题)

如下的10个格子

在这里插入图片描述

填入0~9的数字。要求:连续的两个数字不能相邻。 (左右、上下、对角都算相邻)
一共有多少种可能的填数方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

这道题可以用全排列+判断,也可以用dfs+剪枝
在这里插入图片描述
全排列(递归)

#include<bits/stdc++.h>
using namespace std;
int a[10]={0,1,2,3,4,5,6,7,8,9};
int ans;
bool check(){
    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)
        return false;
    return true;
}
//全排列的套路 
void f(int k){
    if(k==10)
    {//递归出口 
        if(check()) ans++;
        return ; 
    }
    for(int i=k;i<10;i++)//尝试位置i宇位置k交换,以此确定k位 
    { 
        int t=a[i];
        a[i]=a[k];
        a[k]=t;
        f(k+1);
        //回溯 
        int t=a[i];
        a[i]=a[k];
        a[k]=t;
    }
}
int main(){
    f(0);
    cout<<ans<<endl;
    return 0;
}
//运行结果:1580

一般还是推荐这种全排列,速度比递归快一些

#include<bits/stdc++.h>
using namespace std;
int a[10]={0,1,2,3,4,5,6,7,8,9};
int ans;
bool check(){
    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)
        return false;
    return true;
}
//全排列的套路
int main(){
    do{
        if(check()) ans++;
    }
    while(next_permutation(a,a+10));
    cout<<ans<<endl;
    return 0;
}//运行结果:1580
四、快速排序(代码补充)

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

其思想是:先选一个“标尺”, 用它把整个队列过一遍筛子,

以保证:其左边的元素都不大于它,其右边的元素都不小于它。

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

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

#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);
    }
    ___swap(a,p,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;
}

这道题在quicksort函数里q-1,q+1的位置明显说明以中间的q做了分割,而q则是partition函数里返回的j,这个j应该代表的就是一开始的标尺X,但如果直接将x赋值给a[j],会直接覆盖原本的a[j]的值,正确的代码是调用程序中的函数swap,填写结果为swap(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 = ____x&(x+1)______;//代码补充   

    for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);  
    printf("\n");  
}

int main() 
{ 
    f(103);  
    f(12);  
    return 0; 
}
六、 寒假作业(填空题)

现在小学的数学题目也不是那么好玩的。

看看这个寒假作业:

□ + □ = □

□ - □ = □

□ × □ = □

□ ÷ □ = □

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

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

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

请填写表示方案数目的整数。

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

和方格填数思路一模一样,但13!太大,需要等待较长时间,可以提前剪枝(注释部分),不剪枝的话需要运行1分多钟

#include<bits/stdc++.h>
using namespace std;
int a[13]={1,2,3,4,5,6,7,8,9,10,11,12,13};
int ans;
bool check(){
    if(a[0]+a[1]==a[2]&&a[3]-a[4]==a[5]
       &&a[6]*a[7]==a[8]&&a[9]%a[10]==0&&a[9]/a[10]==a[11])
        return true;
    return false;
}
void f(int k)
{
    if(k==13)
    {
        if(check()) ans++;
        return ;
    }
    for(int i=k;i<13;i++)
    {
        int t=a[i];
        a[i]=a[k];
        a[k]=t;

        /*if((k==2&&a[0]+a[1]!=a[2])||(k==5&&a[3]-a[4]!=a[5]))
	  	{
	  		{
	  			int t=a[i];
	  			a[i]=a[k];
	  			a[k]=t;
	  		}
	  		continue;
	  	}*/ //提前剪枝,加快速度
        f(k+1);
        int t=a[i];
        a[i]=a[k];
        a[k]=t;
    }
} 
int main(){
    f(0);
    cout<<ans<<endl;
    return 0;
}//运行结果:64

第二种全排列

#include<bits/stdc++.h>
using namespace std;
int a[13]={1,2,3,4,5,6,7,8,9,10,11,12,13};
int ans;
bool check(){
    if(a[0]+a[1]==a[2]&&a[3]-a[4]==a[5]
       &&a[6]*a[7]==a[8]&&a[9]%a[10]==0&&a[9]/a[10]==a[11])
        return true;
    return false;
}
int main(){
    do{
        if(check())
            ans++;
    }while(next_permutation(a,a+13));
    cout<<ans<<endl;
    return 0;
}
七、剪邮票(填空题)

如【图1.jpg】, 有12张连在一起的12生肖的邮票。

现在你要从中剪下5张来,要求必须是连着的。 (仅仅连接一个角不算相连)

比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

单纯dfs解决不了T型问题,正确思路一个是枚举所有的5张的可能,再检查是不是连通块!

#include<bits/stdc++.h>
using namespace std;
int maze[3][4]={0,0,0,0,0,0,0,0,0,0,0,0};
int a[12]={0,0,0,0,0,0,0,1,1,1,1,1};
int dx[]={-1,0,1,0};
int dy[]={0,1,0,-1}; 
int ans=0;
void dfs(int x,int y){
    if(x>2||x<0||y>3||y<0) return;    
    if(maze[x][y]==0) return;
    maze[x][y]=0;
    for(int i=0;i<4;i++)
    {
        int xx=x+dx[i];
        int yy=y+dy[i];
        dfs(xx,yy);
    }
}
bool check(int a[12])
{
    int k=0;
    int x,y;
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<4;j++)
        {
            if(a[k]==1)
            {
                x=i;
                y=j;
            } 
            maze[i][j]=a[k++];
        }
    }
    dfs(x,y);
    for(int i=0;i<3;i++){
        for(int j=0;j<4;j++){
            if(maze[i][j]==1) return false;
        }
    }
    return true;
}
int main()
{
    do{
        if(check(a)) ans++;
    }while(next_permutation(a,a+12));
    cout<<ans<<endl;
    return 0;
} //运行结果116
八、 四平方和

四平方和定理,又称为拉格朗日定理:

每个正整数都可以表示为至多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 , 不能通过工程设置而省略常用头文件。

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

暴力枚举

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    scanf("%d",&n);
    int a,b,c,d;
    a=n;
    for (int i=0;i<=sqrt(a);i++) {
        int b=a-i*i;
        for (int j=0;j<=sqrt(b);j++) {
            int c=b-j*j;
            for (int k=0;k<=sqrt(c);k++) {
                int d=c-k*k;
                int l=sqrt(d);
                if (l*l==d) {
                    printf("%d %d %d %d\n",i,j,k,l);
                    exit(0);
                }
            }
        }
    }
    return 0;
}
九、密码脱落

X星球的考古学家发现了一批古代留下来的密码。

这些密码是由A、B、C、D 四种植物的种子串成的序列。

仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。

由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。

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

输入一行,表示现在看到的密码串(长度不大于1000)

要求输出一个正整数,表示至少脱落了多少个种子。

例如,输入:

ABCBA

则程序应该输出:

0

再例如,输入:

ABECDCBABC

则程序应该输出:

3

资源约定:

峰值内存消耗 < 256M

CPU消耗 < 1000ms

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

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

注意: main函数需要返回0

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

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

动态规划

在这里插入代码片
十、 最大比例

X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。

并且,相邻的两个级别间的比例是个固定值。

也就是说:所有级别的奖金数构成了一个等比数列。比如:

16,24,36,54

其等比值为:3/2

现在,我们随机调查了一些获奖者的奖金数。

请你据此推算可能的最大的等比值。

输入格式:

第一行为数字N(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 , 不能通过工程设置而省略常用头文件。

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

一开始就没读懂题,原来随机调查了一些获奖者的奖金数的意思,就是要从那些里面随便选几个数出来,额。。。,过段时间补代码!

### 第十三届蓝桥杯 C++ B 题目及题解 #### 试题 A: 空间 对于空间问题,通常涉及计算几何或简单的数学运算。具体到此题,可能涉及到三维坐标系中的距离计算或其他基本的空间关系处理。 ```cpp #include <iostream> using namespace std; int main() { double x1, y1, z1; double x2, y2, z2; cin >> x1 >> y1 >> z1; cin >> x2 >> y2 >> z2; double distance = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1)); cout << fixed << setprecision(2) << distance << endl; return 0; } ``` [^1] #### 试题 B: 卡片 卡片问题般考察的是合数学的知识点或者是字符串操作技巧。这类题目往往需要理解排列合原理以及如何高效地遍历所有可能性来找到最优解法。 ```cpp #include <bits/stdc++.h> using namespace std; string cards[] = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K"}; vector<string> deck(cards, end(cards)); void shuffleDeck(vector<string>& d){ random_shuffle(d.begin(),d.end()); } int main(){ srand(time(NULL)); // 初始化随机数种子 do{ shuffleDeck(deck); for(auto card : deck) cout<<card<<" "; cout<<"\n"; }while(getchar()!='q'); return 0; } ``` [^2] #### 试题 C: 直线 直线问题是关于解析几何的基础应用之,比如求两条直线交点、判断两直线平行与否等问题。解决此类问题的关键在于掌握好斜率的概念及其相关性质的应用方法。 ```cpp struct Line { double a,b,c; // ax+by+c=0 形式的系数表示条直线 }; bool isParallel(Line l1,Line l2){ return abs(l1.a*l2.b-l1.b*l2.a)<EPSILON; } pair<double,double> intersectionPoint(Line l1,Line l2){ double det=l1.a*l2.b-l1.b*l2.a; if(abs(det)>EPSILON){ // 不平行则有唯交点 double px=(l2.c*l1.b-l1.c*l2.b)/det; double py=(l1.c*l2.a-l2.c*l1.a)/det; return make_pair(px,-py); // 注意这里返回的纵坐标取负号是因为我们定义方程c项前面带了个减号 } throw runtime_error("Lines are parallel or coincident"); } ``` [^3] #### 试题 D: 货物摆放 货物摆放示例展示了动态规划算法的实际应用场景。通过构建状态转移表并逐步填充表格中的值直到最终得到全局最优解的过程体现了该类问题的核心思想——分治策略下的最优化选择。 ```cpp const int MAXN=1e5+5; long long dp[MAXN],w[MAXN]; for(int i=1;i<=n;++i){ for(int j=m;j>=v[i];--j){ dp[j]=max(dp[j],dp[j-v[i]]+w[i]); } } cout<<dp[m]<<endl; ``` #### 试题 E: 路径 路径寻找属于图论范畴内的经典难题,无论是广度优先搜索还是深度优先搜索都能很好地解决问题;而当引入权重概念之后,则可以考虑采用Dijkstra算法或是Floyd-Warshall等更高级别的解决方案来进行分析解答。 ```cpp // 使用队列实现BFS查找最短路径长度 queue<int> q; memset(dist,INF,sizeof dist); dist[s]=0;q.push(s); while(!q.empty()){ int u=q.front();q.pop(); for(int v:g[u]){ if(dist[v]==INF){ dist[v]=dist[u]+1; pre[v]=u; q.push(v); } } } if(dist[t]!=INF){ vector<int> path; for(int cur=t;cur!=-1;cur=pre[cur]) path.push_back(cur); reverse(path.begin(),path.end()); printf("%d\n%d\n",dist[t],path.size()-1); for(size_t i=0;i<path.size();++i) printf(i==path.size()-1?"%d\n":"%d ",path[i]); }else puts("-1"); // 如果无法到达终点就输出-1 ``` #### 试题 F: 间显示 间转换是个非常基础但也容易出错的小知识点,尤其是在不同单位之间的相互转化上要特别小心精度丢失的情况发生。下面给出了种较为通用的间格式化函数模板供参考学习之用。 ```cpp stringstream ss; ss<<setfill('0')<<setw(2)<<hour<<':'<<setw(2)<<minute<<':'<<setw(2)<<second; return ss.str(); ``` #### 试题 G: 砝码称重 砝码称重问题可以通过贪心算法快速得出结论。每次选取当前可用的最重量作为本次测量的标准,这样既能保证准确性又能减少不必要的复杂度提升效率。 ```cpp sort(weights.rbegin(),weights.rend()); // 对砝码按降序排序 double total_weight=accumulate(begin(weights),end(weights),(double)0.0); double current_sum=0.0; int count=0; for(double w:weights){ if(current_sum+w<=total_weight/2.0){ ++count; current_sum+=w; }else break; } printf("%.lf%%\n",(current_sum/(total_weight/2))*100); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值