蓝桥杯——算法分析

蓝桥杯比赛:对算法题进行一些整理,以C语言为主。

题目:

1.杨辉三角形

在屏幕上显示杨辉三角形
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
......................................
问题分析与算法设计
杨辉三角形中的数,正是(x+y)的N次方幂展开式各项的系数。本题作为程序设计中具有代表性的题目,求解的方法很多,这里仅给出一种。

从杨辉三角形的特点出发,可以总结出:
1)第N行有N+1个值(设起始行为第0行)
2)对于第N行的第J个值:(N>=2)
当J=1或J=N+1时:其值为1
J!=1且J!=N+1时:其值为第N-1行的第J-1个值与第N-1行第J个值之和
将这些特点提炼成数学公式可表示为:
1 x=1或x=N+1
c(x,y)= c(x-1,y-1)+c(x-1,y) 其它
本程序应是根据以上递归的数学表达式编制的。

源代码:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 
 4 int c(int x,int y)     /*求杨辉三角形中第x行第y列的值*/
 5 {
 6     int z;
 7     if((y==1)||(y==x+1))  return 1;  /*若为x行的第1或第x+1列,则输出1*/
 8     z=c(x-1,y-1)+c(x-1,y);          /*否则,其值为前一行中第y-1列与第y列值之和*/
 9     return z;
10 }
11 void main()
12 {
13     int i,j,n=13;
14     printf("N=");
15     while(n>12)
16         scanf("%d",&n);     /*控制输入正确的值以保证屏幕显示的图形正确*/
17     for(i=0;i<=n;i++)       /*控制输出N行*/
18     {
19         for(j-0;j<24-2*i;j++) printf(" ");  /*控制输出第i行前面的空格*/
20         for(j=1;j<i+2;j++) printf("%4d",c(i,j));    /*输出第i行的第j个值*/
21         printf("\n");
22     }
23     system("pause");
24 }

运行结果:

 

 2.歌德巴赫猜想
     验证:2000以内的正偶数都能够分解为两个素数之和(即验证歌德巴赫猜想对2000以内的正偶数成立)。
问题分析与算法设计:
       为了验证歌德巴赫猜想对2000以内的正偶数都是成立的,要将整数分解为两部分,然后判断出分解出的两个整数是否均为素数。若是,则满足题意;否则重新进行分解和判断。
    程序中对判断是否为素数的算法进行了改进,对整数判断“用从2开始到该整数的一半”改为“2开始到该整数的平方根”。原因何在请自行分析。

源代码:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<math.h>
 4 int flag(int n);
 5 void main()
 6 {
 7     int i,n;
 8     for(i=4;i<=2000;i+=2)/*范围,且保证为偶数时执行循环体*/
 9     {
10         for(n=2;n<i;n++)         /*将偶数i分解为两个整数*/
11             if(flag(n))         /*分别判断两个整数是否均为素数*/
12             {
13                 if(flag(i-n))
14                 {
15                     printf("%10d=%d+%d",i,n,i-n);   /*若均是素数则输出*/
16                     break;
17                 }
18             
19             }
20                 
21             if(n==i) 
22             {
23                 printf("error %d",i);
24                 break;
25             }
26     }
27 } 
28 int flag(int i)           /*判断是否为素数*/
29 {
30     int j;
31     if(i<=1)return 0;
32     if(i==2)return 1;
33     if(!(i%2))return 0;     /*if no,return 0*/
34     for(j=3;j<=(int)(sqrt((double)i)+1);j+=2)/*求平方根*/
35     {
36         if(!(i%j))/*判断是否为素数*/
37         {
38             return 0;
39         }
40             
41     }   
42     system("pause");
43     return 1;              /*if yes,return 1*/
44 
45 }

运行结果:

 

 

3.马克思手稿中的数学题
   
 马克思手稿中有一道趣味数学问题:有30个人,其中有男人、女人和小孩,在一家饭馆吃饭花了50先令;每个男人花3先令,每个女人花2先令,每个小孩花1先令;问男人、女人和小孩各有几人?

题目分析与算法设计:
    设x,y,z分别代表男人、女人和小孩。按题目的要求,可得到下面的方程:
                   x+y+z=30            (1)
                   3x+2y+z=50          (2)
    用方程程序求此不定方程的非负整数解,可先通过(2)-(1)式得:
                   2x+y=20             (3)
(3)式可知,x变化范围是0~10

源代码:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 void main()
 4 {
 5     int x,y,z,count=0;
 6     printf("            Men      Women     Children\n");
 7     printf("==========================================\n");
 8     for(x=0;x<=10;x++)
 9     {
10         y=20-2*x;                     /*x定值据(3)式求y*/
11         z=30-x-y;                     /*由(1)式求z*/
12         if(3*x+2*y+z==50)             /*当前得到的一组解是否满足式(2)*/
13             printf(" %2d:         %d         %d         %d\n",++count,x,y,z);
14     }
15     system("pause");
16 }

运行结果:

 

 



4.谁是窃贼
    公安人员审问四名窃贼嫌疑犯。已知,这四人当中仅有一名是窃贼,还知道这四人中每人要么是诚实的,要么总是说谎的。在回答公安人员的问题中:
        甲说:“乙没有偷,是丁偷的。”
        乙说:“我没有偷,是丙便的。”
        丙说:“甲没有偷,是乙偷的。”
        丁说:“我没有偷。”
    请根据这四人的答话判断谁是盗窃者。

问题分析与算法设计:
    假设A、B、C、D分别代表四个人,变量的值为1代表该人是窃贱。
    由题目已知:四人中仅有一名是窃贱,且这四个人中的每个人要么说真话,要么说假话,而由于甲、乙、丙三人都说了两句话:“X没偷,X偷了”,故不论该人是否说谎,他提到的两人中必有一人是小偷。故在列条件表达式时,可以不关心谁说谎,谁说实话。这样,可以列出下列条件表达式:
        甲说:”乙没有偷,是丁偷的。”        B+D=1
        乙说:“我没有偷,是丙偷有。”        B+C=1
        丙说:“甲没有偷,是乙偷的。”        A+B=1
        丁说:“我没有偷。”                  A+B+C+D=1
    其中丁只说了一句话,无法判定其真假,表达式反映了四人中仅有一名是窃贱的条件。
源代码:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 void main()
 4 {
 5     int i,j,a[4];
 6     for(i=0;i<4;i++)            /*假定只有第i个人为窃贱*/
 7     {
 8         for(j=0;j<4;j++)        /*将第i个人设置为1表示窃贱,其余为0*/
 9             if(j==i)a[j]=1;
10             else a[j]=0;
11         if(a[3]+a[1]==1&&a[1]+a[2]==1&&a[0]+a[1]==1)   /*判断条件是否成立*/
12         {
13             printf("The thief is  ");              /*成立*/
14             for(j=0;j<=3;j++)                   /*输出计算结果*/
15                 if(a[j])printf("%c.",j+'A');
16             printf("\n");
17         }
18     }
19     system("pause");
20 }

运行结果:

 

 



5.迷语博士的难题(1)
    诚实族和说谎族是来自两个荒岛的不同民族,诚实族的人永远说真话,而说谎族的人永远说假话。迷语博士是个聪明的人,他要来判断所遇到的人是来自哪个民族的。
    迷语博士遇到三个人,知道他们可能是来自诚实族或说谎族的。为了调查这三个人是什么族的,博士分别问了他们的问题,这是他们的对话:
    问第一个人:“你们是什么族?”,答:“我们之中有两个来自诚实族。”第二个人说:“不要胡说,我们三个人中只有一个是诚实族的。”第三个人听了第二个人的话后说:“对,就是只有一个诚实族的。”
    请根据他的回答判断他们分别是哪个族的。

问题分析与算法设计:
    假设这三个人分别为A、B、C,若说谎其值为0,若诚实,其值为1。根据题目中三个人的话可分别列出:
        第一个人: a&&a+b+c==2||!a&&a+b+c!=2
        第二个人: b&&a+b+c==1||!b&&a+b+c!=1
        第三个人: c&&a+b+c==1||!c&&a+b+c!=1
    利用穷举法,可以很容易地推出结果。
源代码:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 void main()
 4 {
 5     int a,b,c;
 6     for(a=0;a<=1;a++)       /*穷举每个人是说谎还是诚实的全部情况*/
 7         for(b=0;b<=1;b++)    /*说谎:0   诚实:1*/
 8             for(c=0;c<=1;c++)
 9                 if((a&&a+b+c==2||!a&&a+b+c!=2)    /*判断是否满足题意*/
10                     &&(b&&a+b+c==1||!b&&a+b+c!=1)
11                     &&(c&&a+b+c==1||!c&&a+b+c!=1))
12                 {
13                     printf("A is a %s.\n",a?"honest":"lier");    /*输出判断结果*/
14                     printf("B is a %s.\n",b?"honest":"lier");
15                     printf("C is a %s.\n",c?"honest":"lier");
16                 }
17     system("pause");
18 }

运行结果:

 

 


6.小结

数学题的逻辑 !!!


    

posted @ 2019-11-27 22:44  小高冷  阅读(1085)  评论(1编辑  收藏  举报