2015蓝桥杯C/C++B组真题(1-5)

1.奖券数目

有些人很迷信数字,比如带“4”的数字,认为和“死”谐音,就觉得不吉利。
虽然这些说法纯属无稽之谈,但有时还要迎合大众的需求。某抽奖活动的奖券号码是5位数(10000-99999),要求其中不要出现带“4”的号码,主办单位请你计算一下,如果任何两张奖券不重号,最多可发出奖券多少张。
请提交该数字(一个整数),不要写任何多余的内容或说明性文字。

方法一
数学计算:8x9x9x9x9 = 52488

方法二
分解出号码的每一位,再来判断是否为4,只有这个数中的其中一个位数的数字为4,边记录下来,接着来判断下一个数。

#include <stdio.h>
int ans=0;
int main()
{
	int i;
	for(i=10000;i<100000;i++)
	{
		if(!(i/10000==4 || i%10000/1000==4 || i%1000/100==4 || i%100/10==4 || i%10==4))
		{
			ans++;
		}
	}
	printf("ans = %d\n",ans);
	return 0;
}

输出:52488

方法三:字符串

#include<iostream>
#include<sstream>
#include<string>
using namespace std;

void i2s(int num, string &str){
//stringstream 类的作用是将数字转换成字符串
        stringstream ss;
//将需要转换的数字 num 使用 << 运算符传递给 ss 对象 
        ss << num;
//将转换后的字符串使用 >> 运算符传递给 str 变量 
        ss >> str;
    }
    
int main(){
    int ans=0;
    for(int i=10000;i<=99999;i++){
        string s;
        i2s(i,s);
        
//查找字符串 s 中是否不包含(注意: 不包含用的是 ==)'4'这个字符串 
        if(s.find('4')==string::npos){
            ans++;
        }
    }
    cout<<ans<<endl;
    return 0;
}

string::npos参数
npos 是一个常数,用来表示不存在的位置,类型一般是std::container_type::size_type 许多容器都提供这个东西;取值由实现决定,一般是-1,这样做,就不会存在移植的问题。
find函数
find函数的返回值是整数,假如字符串存在包含关系,其返回值必定不等于npos,但如果字符串不存在包含关系;那么返回值就一定是npos,所以很容易想到用if判断语句来实现。
简单而言:如果存在包含关系find函数返回的就是主串与子串相匹配的下标,如果不存在包含关系就返回。
npos(一个常数,表示不存在)(s.find(“abcdefg”)==string::npos)

2.星系炸弹

在X星系的广袤空间中漂浮着许多X星人造“炸弹”,用来作为宇宙中的路标。
每个炸弹都可以设定多少天之后爆炸。
比如:阿尔法炸弹2015年1月1日放置,定时为15天,则它在2015年1月16日爆炸。
有一个贝塔炸弹,2014年11月9日放置,定时为1000天,请你计算它爆炸的准确日期。
请填写该日期,格式为 yyyy-mm-dd 即4位年份2位月份2位日期。比如:2015-02-19
请严格按照格式书写。不能出现其它文字或符号。

方法一:Excel 非常好用!
在这里插入图片描述
右键单元格–>设置单元格格式–>选日期,然后选星期
就知道那天是星期几了

方法二:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main(){
    int sum=1000;
    int Mdays[12]={31,28,31,30,31,30,31,31,30,31,30,31};
    int Y=2014;
    int M=11;
    int D=9;
    
//2014 年 11 月 09 日距离爆炸有 1000 天, 在此循环 1000 次
    for(int i=1;i<=sum;i++){ 
        D++; //每循环一次则日数加 1 
        if(D>Mdays[M-1]){ //如果日数大于 11 月的日数, 则日数重置为 1, 月数加 1 
            D=1;
            M++;
            if(M>12){ //如果月数大于 12, 则月数重置为 1, 年数加 1. 
                M=1;
                Y++;
                
                //新开始一年之后, 对是否为闰年进行判断 
                if((Y%400==0)||(Y%4==0&&Y%100!=0)){
                    Mdays[1]=29;
                }else{
                    Mdays[1]=28;
                }
            }
        } 
    } 
    cout<<Y<<"-"<<M<<"-"<<D<<endl;
    return 0;
}

输出:2017-08-05

3.三羊献瑞

观察下面的加法算式:
在这里插入图片描述
其中,相同的汉字代表相同的数字,不同的汉字代表不同的数字。
请你填写“三羊献瑞”所代表的4位数字(答案唯一),不要填写任何多余内容。

方法一:暴力破解
e d f g
a b c d
a b f d h

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main(){
    int sum, sum1, sum2;
    for(int a=1;a<=9;a++){ //a 不能等于 0 
        for(int b=0;b<=9;b++){
            if(b!=a){
                for(int c=0;c<=9;c++){
                    if(c!=a&&c!=b){
                        for(int d=0;d<=9;d++){
                            if(d!=a&&d!=b&&d!=c){
                                for(int e=1;e<=9;e++){ //e 不能等于 0 
                                    if(e!=a&&e!=b&&e!=c&&e!=d){
                                        for(int f=0;f<=9;f++){
                                            if(f!=a&&f!=b&&f!=c&&f!=d&&f!=e){
                                                for(int g=0;g<=9;g++){
                                                    if(g!=a&&g!=b&&g!=c&&g!=d&&g!=e&&g!=f){
                                                        for(int h=0;h<=9;h++){
                                                            if(h!=a&&h!=b&&h!=c&&h!=d&&h!=e&&h!=f&&h!=g){
                                                                sum1=e*1000+d*100+f*10+g;
                                                                sum2=a*1000+b*100+c*10+d;
                                                                sum=a*10000+b*1000+f*100+d*10+h;
                                                                if(sum==(sum1+sum2)){
                                                                    printf("%d\n",sum2);
                                                                }
                                                            }
                                                            
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return 0;
}

也可以先推算出a=1,e=9,b=0,再循环,验证

方法二:全排列(next_permutation实现升序,而prev_permutation实现降序)
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。如果这组数有n个,那么全排列数为n!个。
比如a,b,c的全排列一共有3!= 6 种 分别是{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a}。
头文件:#include < algorithm >
next_permutation:求下一个排列组合 
a.函数模板:next_permutation(arr, arr+size);
b.参数说明:
  arr: 数组名
  size:数组元素个数
c.函数功能: 返回值为bool类型,当当前序列不存在下一个排列时,函数返回false,否则返回true, 排列好的数在数组中存储
d.注意:在使用前需要对欲排列数组按升序排序,否则只能找出该序列之后的全排列数。
比如,如果数组num初始化为2,3,1,那么输出就变为了:{2 3 1} {3 1 2} {3 2 1}

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main(){
    int aa[10]={0,1,2,3,4,5,6,7,8,9};  //三,羊,献,瑞,祥,生,辉,气
    int sum=0;
    int sum1=0;
    int sum2=0; 
    int ans=0;
    while(next_permutation(aa,aa+10)){
        if(aa[0]!=0&&aa[4]!=0){
            sum1=aa[4]*1000+aa[3]*100+aa[5]*10+aa[6];
            sum2=aa[0]*1000+aa[1]*100+aa[2]*10+aa[3];
            sum=aa[0]*10000+aa[1]*1000+aa[5]*100+aa[3]*10+aa[7];
            if(sum==(sum1+sum2)){
            break;
            }
        }
    }
    cout<<"祥瑞生辉:"<<endl; 
    cout<<" "<<sum1<<endl;
    
    cout<<"三羊献瑞:"<<endl; 
    cout<<" "<<sum2<<endl;
    
    cout<<"三羊生瑞气:"<<endl;
    cout<<sum<<endl;
    return 0;
}

4.格子中输出

StringInGrid函数会在一个指定大小的格子中打印指定的字符串。
要求字符串在水平、垂直两个方向上都居中。
如果字符串太长,就截断。
如果不能恰好居中,可以稍稍偏左或者偏上一点。
下面的程序实现这个逻辑,请填写划线部分缺少的代码。

#include <stdio.h>
#include <string.h>

void StringInGrid(int width, int height, const char* s)
{
    int i,k;
    char buf[1000];
    strcpy(buf, s);
    if(strlen(s)>width-2) buf[width-2]=0;
    

printf("+");
for(i=0;i<width-2;i++) printf("-");
printf("+\n");

for(k=1; k<(height-1)/2;k++){
    printf("|");
    for(i=0;i<width-2;i++) printf(" ");
    printf("|\n");
}

printf("|");

printf("%*s%s%*s",(width-2-strlen(s))/2," ",buf,(width-strlen(s)-1)/2," ");  //填空
          
printf("|\n");

for(k=(height-1)/2+1; k<height-1; k++){
    printf("|");
    for(i=0;i<width-2;i++) printf(" ");
    printf("|\n");
}    

printf("+");
for(i=0;i<width-2;i++) printf("-");
printf("+\n");    

}

int main()
{
    StringInGrid(20,6,"abcd1234");
    return 0;
}

对于题目中数据,应该输出:
在这里插入图片描述
%*s: 在printf中使用,表示用后面的形参替代的位置,实现动态格式输出。
例如:
printf(“%*s”, 10, s);
意思是输出字符串s,但至少占10个位置,不足的在字符串s左边补空格,这里等同于printf(“%10s”, s);

本题:填空处要输出的是字符的那一行
左侧空格数:( width - strlen(s) - 2 ) / 2
右侧空格数:( width - strlen(s) - 1 ) / 2

5.九数组分数

1,2,3…9 这九个数字组成一个分数,其值恰好为1/3,如何组法?
下面的程序实现了该功能,请填写划线部分缺失的代码。

#include <stdio.h>

void test(int x[])
{
	int a = x[0]*1000 + x[1]*100 + x[2]*10 + x[3];
	int b = x[4]*10000 + x[5]*1000 + x[6]*100 + x[7]*10 + x[8];
    if (a*3==b) printf("%d / %d\n", a, b);
}

void f(int x[], int k)
{
	int i,t;
	if(k>=9){     //形成一个排列
		test(x);
		return;
	}
	
	for(i=k; i<9; i++){
		{t=x[k]; x[k]=x[i]; x[i]=t;}       //交换
		f(x,k+1);  //递归下探
		{t = x[k];x[k] = x[i];x[i] = t;}  // 回溯     填空
	}
}
	
int main()
{
	int x[] = {1,2,3,4,5,6,7,8,9};
	f(x,0);	
	return 0;
}

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

全排列,交换
本题考查的是回溯,算法是一共九个数,在第一个数选定之后,选定第二个数,再选定第三个数……
常见的方法有两种:
1.交换法
2. 记录数组法
本题中题目为了避免重复给出的是交换法。
解释:i = 0时会将第一个数(k=0)和后面的数(i从0到9)依次交换(x[k]与x[i]交换),每完成这样一次交换后会调用下一位(k+1)的交换,这时i = 1会将第二个数(k=1)和后面的数(i从1到9)一次交换……
回溯算法的框架: https://zhuanlan.zhihu.com/p/93530380
result = []
def backtrack(路径, 选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择

仅供学习,部分资料来源网络。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值