【蓝桥杯】2019年第十届蓝桥杯大学生B组C/C++真题——试题F:特别数的和


 
  写在前面:这篇博客的代码部分其实很早之前就写好了。
  写这篇博客的背景:舍友这两年都有参加蓝桥杯,看他这么勤奋、努力,相比于自己的平平无奇,心里不是滋味。
  写这篇博客的缘由:在今年蓝桥杯成绩出来后得知他又得了二等奖,我向他要了试题的链接 2019年第十届蓝桥杯大学生B组C/C++真题,看了一下题目前面的都不会…直到看到了试题F,感觉自己可以做,于是当晚就写好了(本来打算当晚就发表出去的…)。写完后给舍友看,舍友指出了一些问题,那时候我就觉得自己写的很没有技术含量(卑微),于是乎就没有然后了。
  直到昨天才发现原来舍友有写博客的习惯,进去他的博客看了一下,30篇原创,一直默默地写自己的心得、体会,把自己的点点滴滴都写进去,这时我才发现,写博客从来都不是写给谁看的(虽然被很多人看到会很有成就感 ,嘻嘻),重要的是自己总结不断成长。这才有了这第一篇自己的博客。
 
 
 

C语言实现,试题F:特别数的和

 
 
 
【问题的描述】
小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),在 1 到40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。
  请问,在 1 到 n 中,所有这样的数的和是多少?
  
【输入格式】
  输入一行包含两个整数 n。
  
【输出格式】
  输出一行,包含一个整数,表示满足条件的数的和。
  
【样例输入】
  40
  
【样例输出】
  574
  
【评测用例规模与约定】
  对于 20% 的评测用例,1 ≤ n ≤ 10。
  对于 50% 的评测用例,1 ≤ n ≤ 100。
  对于 80% 的评测用例,1 ≤ n ≤ 1000。
  对于所有评测用例,1 ≤ n ≤ 10000。

 
 
 

思路

  看到题目脑袋里就闪过if(),通过穷举的方式列出各种情况下含有2、0、1、9的情况,然后把符合情况的数字相加,最后得到的结果就是特别数的和。
 
 
 

代码

#include<stdio.h>

//输出1~10000内任意含有2、0、1、9的数字
int main()
{
    //number为输入的数字
    //i用来验证是否含有2、0、1、9
    //sum为输出特别数的和
    int number = 1;
    int i = 1;
    int sum = 0;


    //从键盘读取一个数的值赋给number
    printf("输入一个整数n: \n");
    scanf("%d",&number);


    //打印1-number里符合要求的数
    printf("含有2、0、1、9的整数有: ");
    for(i;i<=number;i++)
    {
        int sum_g = i%10;//个位数
        int sum_s = i/10;//十位数
        int sum_b = i/100;//百位数
        int sum_q = i/1000;//千位数



        //1~9里个位数含有2、0、1、9
        if(i<10)
        {
            if(sum_g==2||sum_g==0||sum_g==1||sum_g==9)
            {
                sum += i ;
                printf("%d ",i);
            }
        }



        //1~99里十位数含有2、0、1、9
        if(i>=10&&i<100)
        {
            //十位数含有2、0、1、9的数
            if(sum_s==2||sum_s==0||sum_s==1||sum_s==9)
            {
                sum += i ;
                printf("%d ",i);
            }



            //十位数不含2、0、1、9的数,但个位数含有2、0、1、9的数
            if(!(sum_s==2||sum_s==0||sum_s==1||sum_s==9))
            {
                if(sum_g==2||sum_g==0||sum_g==1||sum_g==9)
                {
                    sum += i ;
                    printf("%d ",i);
                }
            }
        }



        //1~999里十位数含有2、0、1、9
        if(i>=100&&i<1000)
        {
            //百位数含有2、0、1、9的数
            if(sum_b==2||sum_b==0||sum_b==1||sum_b==9)
            {
                sum += i ;
                printf("%d ",i);
            }



            //百位数不含2、0、1、9的数,但个、十位数含有2、0、1、9的数
            if(!(sum_b==2||sum_b==0||sum_b==1||sum_b==9))
            {
                int j = i - i/100*100;//转换成两位数
                int sum_s_1 = j/10;



                //十位数含2、0、1、9
                if(sum_s_1==2||sum_s_1==0||sum_s_1==1||sum_s_1==9)
                {
                    sum += i ;
                    printf("%d ",i);
                }



                //十位数不含2、0、1、9的数,但个位数含有2、0、1、9的数
                if(!(sum_s_1==2||sum_s_1==0||sum_s_1==1||sum_s_1==9))
                {
                    if(sum_g==2||sum_g==0||sum_g==1||sum_g==9)
                    {
                        sum += i ;
                        printf("%d ",i);
                    }
                }
            }
        }



        //1~10000里十位数含有2、0、1、9
        if(i>=1000&&i<=10000)
        {
            //1000~9999里十位数含有2、0、1、9
            if(i>=1000&&i<=9999)
            {
                //千位数含有2、0、1、9的数
                if(sum_q==2||sum_q==0||sum_q==1||sum_q==9)
                {
                    sum += i ;
                    printf("%d ",i);
                }



                if(!(sum_q==2||sum_q==0||sum_q==1||sum_q==9))
                {
                    int k = i - i/1000*1000;//转换成三位数
                    int sum_b_1 = k/100;

                    int j = i - i/100*100;//转换成两位数
                    int sum_s_1 = j/10;



                    //百位数含2、0、1、9的数
                    if(sum_b_1==2||sum_b_1==0||sum_b_1==1||sum_b_1==9)
                    {
                        sum += i ;
                        printf("%d ",i);
                    }



                    //除去百位数后剩下十位与个位含2、0、1、9的数ss
                    if(!(sum_b_1==2||sum_b_1==0||sum_b_1==1||sum_b_1==9))
                    {
                        //十位数含2、0、1、9的数
                        if(sum_s_1==2||sum_s_1==0||sum_s_1==1||sum_s_1==9)
                        {
                            sum += i ;
                            printf("%d ",i);
                        }



                        //十位数不含2、0、1、9的数,但个位数含有2、0、1、9的数
                        if(!(sum_s_1==2||sum_s_1==0||sum_s_1==1||sum_s_1==9))
                        {
                            if(sum_g==2||sum_g==0||sum_g==1||sum_g==9)
                            {
                                sum += i ;
                                printf("%d ",i);
                            }
                        }
                    }

                }
            }



            if(i==10000)
            {
                sum += i ;
                printf("%d ",i);
            }

        }
    }
    printf("\n所有含有2、0、1、9的数的和为: %d",sum);
    return 0;
}

 
 
 
 

效果图

试题F(1)
试题F(2)
 
 
 

总结

  事实上这样子的代码太冗余了…

  1.把所有代码都放for()循环里,导致变量i每条件符合一个if()就要循环一遍,这可能就是运行结果超过1s的原因(虽然从输入数字按回车开始,到显示求和结果结束,感觉连1s都没有)

  2.好多代码都可以重复使用(例如1<=n<=100里就包含了1<=n<=10和1<=n<=100两个判断if())

  改进的方法:把每个if()写成一个函数,需要用到的时候就调用(虽然主函数还是会用到if,手动滑稽),每调用一次函数就i++

  

终极方案

  刚刚在CSDN看到一位大佬写的代码,同样的问题,大佬只用了30行,运行起来简直比我自己写的代码好太多了!!!下面附上大佬的博客原文(←点击查看原文)

  按照我的思想,通过if()判断每一位是否含有2、0、1、9,而且代码都写死了(只限于1<=n<=10000的数字,也没有判断输入是否合法)
  而大佬的思想是通过一个函数来找出特别的数,然后累加求和
  根据我对大佬的代码的理解,我向大佬的代码添加了一些注释。从黑盒视角看int solve(int i),solve(i)获得一个整数i,判断这个数是否含为特别的数,若是则返回1,若不是则返回0。
   整个特别的数求和的过程可以简化为
   1. 从键盘获得一个数n
   2. 通过for()循环和solve()函数找出1~ n中特别的数然后进行累加(也可以看成通过for()循环穷举出1~n的数,然后用solve()函数筛选出特别的数,最后求和)

  
  
  为了方便大家理解函数solve(),我以i=234为例,手工画了个UML图(原谅我没有画UML的软件)
solve()UML图

//#include <iostream>
#include <stdio.h>
int solve(int n);
int main( )
{
	int n,i,sum=0;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		if(solve(i)==1)//条件为真,加
		{
			sum+=i;
//			printf("%d ",i);//输出每次加的数
		}
	}
	printf("%d",sum);
	return 0;
}
int solve(int i)
{
	int x;
	//这个while循环是用来检验输入的数字i的最后一位是否含有2、0、1、9
	//而通过对i=i/10,来使小数点向左移一位,检测此时的最后一位是否含有2、0、1、9
	//这样写的好处是代码简洁、效率高,和我自己写的相比...这样子写真是太完美了
	//这里顺便提一下,可以用循环的地方通常都可以使用递归
	while(i)
	{
		x=i%10;//从个位开始
		if(x==2||x==0||x==1||x==9)//只要包含其中的任意一个数,结果都为真
        {
            return 1;
        }
        i=i/10;//移位
	}
	return 0;
}

  不积硅步无以至千里,不积小流无以成江海。学习重在积累,好记性不如烂笔头,加油!

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值