【算法】算法的艺术(一)

火车托运费的计算

   设乘坐火车托运行李时按下列式子收费:

                    0                (0<=x<=20)

    应交费用y =    (x�C20) * 2         (20<x<=40)

                     (x�C40) * 5 + 40     (x>40)


   编一个程序用来计算应交金额。

  实例解析:

   这是第三章中的一个例题(当时是用switch处理的),是一个选择结构的实例,收费情况共分三种。

   本题可以采用三种方法来编程:

   (1) 用三个单独的if语句,每个if语句处理一种情况;

   (2) 用嵌套的if语句处理,需两个if语句;

   (3) 用switch语句。

方法一:用单独的if语句

  
  
  
  
  1. #include <stdio.h>

  2. int main()

  3. {

  4. int x, y;

  5.   scanf(“%d”, &x);

  6. if(x <= 20)

  7.     y = 0;

  8. if(x > 20 && x <= 40)

  9.     y = (x-20)*2;

  10. if(x > 40)

  11.     y = (x�C40)*5 + 40;

  12.   printf(“y = %d\n”, y);

  13.   getch();

  14. return 0;

  15. }


注意:

if(x > 40)一行,不能写成else,原因请参看第3章3.13中的if语句常见错误。

方法二:用嵌套的if语句

  
  
  
  
  1. #include <stdio.h>

  2. int main()

  3. {

  4.   int x, y;

  5.   scanf(“%d”, &x);

  6.   if(x <= 20)

  7. y = 0;

  8. else if(x <= 40)  //在x>=20不成立的情况下,若x<=40

  9. y = (x-20)*2;

  10.   else  //在前面两个条件都不成立的情况下

  11. y = (x�C40)*5 + 40;

  12.   printf(“y = %d\n”, y);

  13.   getch();

  14.   return 0;

  15. }

方法三:用switch语句

  
  
  
  
  1.  #include <stdio.h>

  2. int main()

  3. {

  4.    int x, y;

  5.    scanf(“%d”, &x);

  6.    switch(x/20)  

  7.    {

  8.      case 0:   y = 0;  break;

  9.        case 1:   y = (x-20)*2;  break;

  10.        default:  y = (x�C40)*5 + 40;

  11.     }

  12.    printf(“y=%d\n”, y);

  13.    getch();

  14.    return 0;

  15. }


找小偷

   警察局抓了a、b、c、d 共4名盗窃嫌疑犯,但只有一人是小偷。审讯中,a不承认自己是小偷,b说c是小偷,c指认d为小偷,d说c冤枉他。已知4人中有3人说的是真话,请问谁是小偷?

   实例解析:

   本实例的目的是让读者学会把逻辑值当整数来使用。

   C中的逻辑值要么为1,要么为0。将几个关系(或逻辑)表达式相加,由结果可以知道其中有几个表达式是成立的。

   由题意知,4个人都是嫌疑犯,所以我们定义一个变量x,使之分别取值1、2、3、4,分别代表a、b、c、d是小偷的4种情况。

   对于x的每一个取值,我们判断下面的4个表达式有几个成立。

   (1)  x != 1        //小偷不是a

   (2)  x == 3       //小偷是c

   (3)  x == 4       //小偷是d

   (4)  x != 4        //小偷不是d

   判断的方法是:将4个表达式的值相加,若等于3,表示三个人说的是真话,符合题意,输出结果,否则,不符合题意,跳过。

   下面是程序代码:

  
  
  
  
  1. #include <stdio.h>

  2. int main()

  3. {

  4.     int x;

  5.     for(x = 1; x <= 4; x++)

  6.       if((x!=1) + (x==3) + (x==4) + (x!=4) == 3)

  7.          printf(“%c是小偷!\n”, x+64);

  8.     getch();

  9.     return 0;

  10. }



判断整数能被3、5、7中的哪些数整除

   键盘输入一个整数,判断能被3、5、7中的几个数整数,并且指出这几个数。

   实例解析:

   这个题目可以用3个if语句分别检查能否被3、5、7整除,但这种最普通的算法效率较低。

   这里我们介绍一种简单的方法,利用实例3所介绍的技巧:将几个关系表达式相加,可以知道有几个表达式是成立的。

   求解:s = (x%3==0) + (x%5 == 0) + (x%7 == 0)

   (1)若s 值为3,则x可同时被3个数整除

   (2)若s为2,则只能同时被其中2个数整除。

   (3)若s为1,则只能被其中1个数整除。

   (4)若s为0,则不能被其中任何数整除。

   但是,这样设计有一个问题,当s = 2或s = 1时,我们只知道x可以被几个数整数,但能被哪些数整除却不能确定。

   为此,我们这样设计:用一个字节的后三位分别表示能否被3、5、7整除。若x能被3整除,我们让最后一位为1,若能被5整除,让倒数第2位为1,若能被7整除,让倒数第3位为1。共有8种可能:

   (1)00000000

   (2)00000001

   (3)00000010

   (4)00000011

   (5)00000100

   (6)00000101

   (7)00000110

   (8)00000111

   通过检查该字节的值,可以得到本实例所要的结论。

   程序代码如下:

  
  
  
  
  1. #include <stdio.h>

  2. int main()

  3. {

  4.    int x;

  5.    char s;

  6.    scanf(“%d”, &x);

  7. s = (x%3==0) + (x%5==0)*2 + (x%7==0)*4;  

  8.    switch(s)

  9.    {

  10.      case 0:   printf(“none\n”); break;

  11.      case 1:   printf(“3\n”);     break;

  12.      case 2:   printf(“5\n”);     break;

  13.      case 3:   printf(“3,5\n”);   break;

  14.      case 4:   printf(“7\n”);     break;

  15.      case 5:   printf(“3,7\n”);   break;

  16.      case 6:   printf(“5,7\n”);   break;

  17.      case 7:   printf(“3,5,7\n”); break;

  18.      default:  printf(“error!\n”);  

  19.    }

  20.    return 0;

  21. }


找假货

   有5箱产品,每箱20件,但其中有几箱里全是假货。已知正品每件100克,假货比正品轻10克,问能否用天平只称一次,找出所有装假货的箱子?

   实例解析:

   本题可以先这样考虑:每箱取出一件产品,共取5件,一起放在天平上称一次,如果总重490克,说明比正常情况少了10克,其中必定有一件是假货,推断出只有一箱假货。如果比正常少20克,则有两箱假货,如果少30克,有三箱假货……

   但是,这样只能知道有几箱假货,不知道哪箱是假货。为此,我们给每个箱子加上权重:即每个箱子取出的产品数目不同。

   我们想到,可以在5个箱子中分别取1、2、3、4、5件产品,但这样的算法依然存在问题:当总重470克时,有可能1、2号箱是假货,还有可能3号箱是假货,还是不能确定哪些箱是假货。

   正确的取法应该是:分别在5个箱子中取1、2、4、8、16件产品,这样就不会出现分辨不清的情况了。例如若总重430克,少了70克,则一定是前三箱是假货。

   下面是程序代码:

  
  
  
  
  1. #include <stdio.h>

  2. int main()

  3. {

  4. int w[5] = {100,90,100,90,90}; //分别是5个箱子里一件产品的重量

  5. int sum = 0, i, k = 1, m;

  6. for(i = 0; i < 5; i++ )  

  7.    {

  8.       sum += w[i]*k;  

  9.       k *= 2;  

  10.     }

  11.     m = (100*31 �C sum)/10 ;        // 计算其中有多少件假货

  12.     k = 16;                           //  k先取第5箱的权重

  13. for(i = 5; i >= 1; i--)

  14.     {

  15. if(m >= k)

  16.       {

  17.            printf(“第%d箱是假货\n”, i);

  18.            m -= k;  

  19.          }                  

  20.         k /= 2;  // k变为下一个要处理箱的权重

  21.       }  

  22.    getch();

  23. return 0;

  24.    }


   上面代码的最后一段也可以采用位操作来完成:


  
  
  
  
  1. m = (100*31 �C sum)/10 ; // 计算其中有多少件假货

  2. for(i = 1; i <= 5; i++)  

  3. {

  4. if(m & 1)

  5.      printf(“第%d箱是假货\n”, i);

  6.      m >>= 1;      

  7. }    


计算某天是一年中的第几天

   键盘输入一个年月日,计算该日期在该年中是第几天。

   实例解析:

   这也是第三章中的一个例题(参看例3.3),在例3.3中是用switch语句来编程的,这里我们用循环的方法。

   程序设计思路是:用一个数组存放12个月份的天数(实际上第12月的数据无用),假设month=5,则需要先把前4个月的天数(即下面数组的第1~4个元素)加起来,再加上5月份的日期(即day),若是闰年,再加1。

  
  
  
  
  1. #include<stdio.h>

  2. int main( )

  3. {

  4. int  year, month, day;

  5. int m[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};  

  6. int  i, n = 0;

  7.     scanf(“%d%d%d”, &year, &month, &day);

  8. for(i = 1; i < month; i++)

  9.        n += m[i];

  10.    n += day;

  11. if((year%4==0 && year%100 != 0 || year%400 == 0 ) && month>=3 )

  12.        n++;

  13.    printf(“%d\n”, n);

  14.    getch();

  15. return 0;

  16.   }



你可能感兴趣的:(数据结构,算法,mystery)