2013年第四届蓝桥杯C/C++组真题补充训练(一,2017.3.4)未完待续

来源:互联网 发布:acca伦敦大学硕士知乎 编辑:程序博客网 时间:2024/04/30 00:33

1. (C组T1 3')猜年龄


    美国数学家维纳(N.Wiener)智力早熟,11岁就上了大学。他曾在1935~1936年应邀来中国清华大学讲学。


    一次,他参加某个重要会议,年轻的脸孔引人注目。于是有人询问他的年龄,他回答说:


    “我年龄的立方是个4位数。我年龄的4次方是个6位数。这10个数字正好包含了从0到9这10个数字,每个都恰好出现1次。”


    请你推算一下,他当时到底有多年轻。


    通过浏览器,直接提交他那时的年龄数字。
    注意:不要提交解答过程,或其它的说明文字。

【分析】循环+枚举

源代码:

#include <stdio.h>#include <math.h>int main(){int age;int pow3,pow4;for(age=10;age<=30;age++){pow3=pow(age,3);pow4=pow(age,4);printf("age=%d pow3=%d pow4=%d\n",age,pow3,pow4);} return 0;}
程序截图:


【答案】18

※2. (C组T3 8’)振兴中华


    小明参加了学校的趣味运动会,其中的一个项目是:跳格子。

    地上画着一些格子,每个格子里写一个字,如下所示:(也可参见p1.jpg)

从我做起振
我做起振兴
做起振兴中
起振兴中华


    比赛时,先站在左上角的写着“从”字的格子里,可以横向或纵向跳到相邻的格子里,但不能跳到对角的格子或其它位置。一直要跳到“华”字结束。

    要求跳过的路线刚好构成“从我做起振兴中华”这句话。

    请你帮助小明算一算他一共有多少种可能的跳跃路线呢?

答案是一个整数,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。

【分析】

法一:笔算、数路线

法二:二维数组+递归的综合应用(思想很重要!)

        首先把“从我做起,振兴中华”这八个字按照0~7的顺序编好,然后把这个方格存放在一个4*5的二维数组array里面,同时,设定一个同样大小的flag数组来存放行走轨迹,最后还要设定一个road_flag[7]的数组来记录行走的步子是横向还是纵向。
        接下来就是利用递归遍历这个二维数组,
  递归过程是:从0,0开始,横着或者竖着前进,向前前进一格的条件就是没有超出范围,并且下一格的数字比这一格大1。每次前进一格后,就把flag数组中相应的位置标记为1,同时根据行走的步子的方向来对road_flag中的相应步数进行标记。(这里只需考虑向右走和向下走两种情况)
  如果到达了华这个字(相应的数字为7),那么就到了递归出口,判断这一条路径是否符合要求,是否能够输出,然后返回。
  函数返回之后,要把相应的路径标记和步子标记清除。
  就这样一直遍历,直到把所有的路径都找出来!

参考源代码:

#include <stdio.h>#include <string.h>#define ROW 4#define COL 5int count;                                   //统计路径的次数int flag[ROW][COL];                          //路径标记int road_flag[ROW+COL-1];                    //步子标记 1-向右走,2-向下走 int road_count;                              //记录方案总数(走的步数) int road(int arr[][COL],int row,int col){    flag[row][col]=1;                        //标记路径--每次前进一格后,就把flag数组中相应的位置标记为1    if(arr[row][col]==7)                     //到达"华"这个字的位置     {    count++;    printf("No.%d:\n",count);    //判断这一条路径是否符合我们的要求    //if(1==road_flag[0] && 2==road_flag[1] && 2==road_flag[2] && 2==road_flag[3] && 1==road_flag[4] && 1==road_flag[5] && 1==road_flag[6])        //{for(int rloop=0;rloop<ROW;rloop++)        {        for(int cloop=0;cloop<COL;cloop++)        if(1 == flag[rloop][cloop])              //被标记的点,说明该点在行走路线上             printf(" # ");        else            printf(" ^ ");        printf("\n");        }    //}     return 0;    }        //横向走    if(col+1<COL && arr[row][col+1]==arr[row][col]+1)   //列号+1不超边界,且下一位置对应的数=上一位置对应的数+1     {    road_flag[road_count] = 1;                      //说明可以横向走,并用1标记原来所在的位置     road_count++;    road(arr,row,col+1);                            //递归进行上述过程         //取消路径和步子标记(此过程也是递归进行的)     flag[row][col+1] = 0;    road_count--;    road_flag[road_count] = 0;    }        //纵向走    if(row+1<ROW && arr[row+1][col]==arr[row][col]+1)   //行号+1不超边界,且下一位置对应的数=上一位置对应的数+1     {    road_flag[road_count] = 2;                      //说明可以横向走,并用2标记原来所在的位置     road_count++;    road(arr,row+1,col);                            //递归进行上述过程     //取消路径和步子标记(此过程也是递归进行的)     flag[row+1][col] = 0;    road_count--;    road_flag[road_count] = 0;    }}int main()                                   //"从我做起振兴中华"8个字依次对应数字0~7 {    int array[ROW][COL]={          {0,1,2,3,4},    {1,2,3,4,5},    {2,3,4,5,6},    {3,4,5,6,7}};    road(array,0,0);                         //从起点开始,递归遍历     printf("count = %d\n",count);    return 0;}
程序截图:






【答案】35

※3. (C组T4 13’)幻方填空

    幻方是把一些数字填写在方阵中,使得行、列、两条对角线的数字之和都相等。

    欧洲最著名的幻方是德国数学家、画家迪勒创作的版画《忧郁》中给出的一个4阶幻方。

    他把1,2,3,...16 这16个数字填写在4 x 4的方格中。

    如图p1.jpg所示,即:

16 ?  ?  13
?  ?  11 ?
9  ?  ?  *
?  15 ?  1


    表中有些数字已经显露出来,还有些用?和*代替。

    请你计算出? 和 * 所代表的数字。并把 * 所代表的数字作为本题答案提交。

答案是一个整数,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。

【分析】

对比题型:打印n阶魔方阵(n为奇数)

4. (C组T5 5’)公约数公倍数



    我们经常会用到求两个整数的最大公约数和最小公倍数的功能。


    下面的程序给出了一种算法。


    函数 myfunc 接受两个正整数a,b


    经过运算后打印出 它们的最大公约数和最小公倍数。


    此时,调用 myfunc(15,20)  


将会输出:
5
60 


// 交换数值
void swap(int *a,int *b)
{
   int temp;
   temp=*a;
   *a=*b;
   *b=temp;
}


void myfunc(int a, int b)
{
   int m,n,r;  
   if(a<b) swap(&a,&b);
   m=a;n=b;r=a%b;
   while(r!=0)
   {
    a=b;b=r;
    r=a%b;
   }
   printf("%d\n",b);  // 最大公约数 
   printf("%d\n", ____________________________________);  // 最小公倍数 
}


请分析代码逻辑,并推测划线处的代码,通过网页提交。
注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!

【分析】辗转相除法

填空后代码:

#include <stdio.h>// 交换数值void swap(int *a,int *b){   int temp;   temp=*a;   *a=*b;   *b=temp;}void myfunc(int a, int b){   int m,n,r;     if(a<b)   swap(&a,&b);   m=a;   n=b;   r=a%b;   while(r!=0)   {    a=b;b=r;    r=a%b;   }   printf("%d\n",b);       // 最大公约数    printf("%d\n", m*n/b);  // 最小公倍数 填空位置 }int main(){int a,b;while(scanf("%d %d",&a,&b)!=EOF)myfunc(a,b);return 0;}
程序截图:


【答案】m*n/b

5. (A组T2 6’)排它平方数


    小明正看着 203879 这个数字发呆。


    原来,203879 * 203879 = 41566646641


    这有什么神奇呢?仔细观察,203879 是个6位数,并且它的每个数位上的数字都是不同的,并且它平方后的所有数位上都不出现组成它自身的数字。


    具有这样特点的6位数还有一个,请你找出它!


    再归纳一下筛选要求:
    1. 6位正整数
    2. 每个数位上的数字不同
    3. 其平方数的每个数位不含原数字的任何组成数位


答案是一个6位的正整数。


请通过浏览器提交答案。
注意:只提交另一6位数,题中已经给出的这个不要提交。
注意:不要书写其它的内容(比如:说明性的文字)。

【分析】循环+数位分离+重复判断。特别注意平方数的数据类型要设置为long long int型避免溢出问题。

源代码:

#include <stdio.h>long long int Judge(long long int a[],long long int n)               //判断数a的各位数是否有重复 {long long int i,j;long long int flag=1;for(i=0;i<n;i++){for(j=i+1;j<n;j++){if(a[i]==a[j]){flag=0;break;}}}return flag;}long long int Judge(long long int a[],int m,long long int b[],int n) //判断数a与数b的各位数是否有重复 {long long int i,j;long long int flag=1;for(i=0;i<m;i++){for(j=0;j<n;j++){if(a[i]==b[j]){flag=0;break;}}}return flag;}int main(){long long int i,j,k;long long int num1[20],num2[20];long long int t,tt,pownum;for(i=100000;i<999999;i++){pownum=i*i;t=i,tt=pownum;j=0;while(t){num1[j++]=t%10;t/=10;}if(Judge(num1,j)){k=0;while(tt){num2[k++]=tt%10;tt/=10;}if(Judge(num1,j,num2,k))printf("%lld*%lld=%lld\n",i,i,pownum);}}return 0;} 
程序截图:


【答案】639172

6. (A组T4 13')颠倒的价牌


    小李的店里专卖其它店中下架的样品电视机,可称为:样品电视专卖店。


    其标价都是4位数字(即千元不等)。


    小李为了标价清晰、方便,使用了预制的类似数码管的标价签,只要用颜色笔涂数字就可以了(参见p1.jpg)。


    这种价牌有个特点,对一些数字,倒过来看也是合理的数字。如:1 2 5 6 8 9 0 都可以。这样一来,如果牌子挂倒了,有可能完全变成了另一个价格,比如:1958 倒着挂就是:8561,差了几千元啊!! 


    当然,多数情况不能倒读,比如,1110 就不能倒过来,因为0不能作为开始数字。


    有一天,悲剧终于发生了。某个店员不小心把店里的某两个价格牌给挂倒了。并且这两个价格牌的电视机都卖出去了!


    庆幸的是价格出入不大,其中一个价牌赔了2百多,另一个价牌却赚了8百多,综合起来,反而多赚了558元。


    请根据这些信息计算:赔钱的那个价牌正确的价格应该是多少?


答案是一个4位的整数,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。

【分析】

源代码:

#include <stdio.h>int main(){int i,j,p1,p2,t;int p,a[4];int reversep1,reversep2;//int a[7]={1,2,5,6,8,9,0};//int reverse[7]={1,2,5,9,8,6,0};for(p1=1000;p1<=9999;p1++){i=0;t=p1;while(t){a[i++]=t%10;t/=10;}for(p=0;p<4;p++){if(a[p]==6)a[p]=9;else if(a[p]==9)a[p]=6;}reversep1=1000*a[0]+100*a[1]+10*a[2]+a[3];for(p2=1000;p2<=9999;p2++){j=0;t=p2;while(t){a[j++]=t%10;t/=10;}for(p=0;p<4;p++){if(a[p]==6)a[p]=9;else if(a[p]==9)a[p]=6;}reversep2=1000*a[0]+100*a[1]+10*a[2]+a[3];//printf("%d %d %d %d\n",p1,reversep1,p2,reversep2);if((reversep1-p1>-300 && reversep1-p1<-200) && (reversep2-p2>800 && reversep2-p2<900) && (reversep1+reversep2-p1-p2==558))printf("%d %d %d %d\n",p1,reversep1,p2,reversep2);}}return 0;} 
程序截图:


【答案】9088

7. (A组T6 10')逆波兰表达式


    正常的表达式称为中缀表达式,运算符在中间,主要是给人阅读的,机器求解并不方便。


    例如:3 + 5 * (2 + 6) - 1


    而且,常常需要用括号来改变运算次序。


    相反,如果使用逆波兰表达式(前缀表达式)表示,上面的算式则表示为:


    - + 3 * 5 + 2 6 1


    不再需要括号,机器可以用递归的方法很方便地求解。


    为了简便,我们假设:


    1. 只有 + - * 三种运算符
    2. 每个运算数都是一个小于10的非负整数
    
    下面的程序对一个逆波兰表示串进行求值。
    其返回值为一个结构:其中第一元素表示求值结果,第二个元素表示它已解析的字符数。


struct EV
{
int result;  //计算结果 
int n;       //消耗掉的字符数 
};


struct EV evaluate(char* x)
{
struct EV ev = {0,0};
struct EV v1;
struct EV v2;


if(*x==0) return ev;

if(x[0]>='0' && x[0]<='9'){
ev.result = x[0]-'0';
ev.n = 1;
return ev;
}

v1 = evaluate(x+1);
v2 = _____________________________;  //填空位置

if(x[0]=='+') ev.result = v1.result + v2.result;
if(x[0]=='*') ev.result = v1.result * v2.result;
if(x[0]=='-') ev.result = v1.result - v2.result;
ev.n = 1+v1.n+v2.n;


return ev;
}

请分析代码逻辑,并推测划线处的代码,通过网页提交。
注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!

【分析】前中后缀表达式的求值(结合数据结构栈的内容)

填空后代码:

#include <stdio.h>#define maxlen 105struct EV{int result;  //计算结果 int n;       //消耗掉的字符数 };struct EV evaluate(char* x){struct EV ev = {0,0};struct EV v1;struct EV v2;if(*x==0) return ev;if(x[0]>='0' && x[0]<='9'){ev.result = x[0]-'0';ev.n = 1;return ev;}v1 = evaluate(x+1);v2 = evaluate(x+v1.n+1);  //填空位置if(x[0]=='+') ev.result = v1.result + v2.result;if(x[0]=='*') ev.result = v1.result * v2.result;if(x[0]=='-') ev.result = v1.result - v2.result;ev.n = 1+v1.n+v2.n;return ev;}int main(){EV v=evaluate("-+3*5+261");printf("%d\n",v.result);return 0;}
程序截图:


【答案】42

0 0
原创粉丝点击