程序设计入门经典

最近开始初步研究高精度算法,以下摘自网上大神的程序,非原创
  1. //高精度除以低精度;
  2. //算法:按照从高位到低位的顺序,逐位相除。
  3. //在除到第j位时,该位在接受了来自第j+1位的余数后与除数相除,如果最高位为零,则商的长度减一。

  4. #include <stdio.h>
  5. #include <string.h>
  6. #define N 500

  7. int main()
  8. {
  9.     int a[N] = {0}, c[N] = {0};
  10.     int i, k, d=0, b;
  11.     char a1[N];
  12.     printf("Input 被除数:");
  13.     scanf("%s", a1);
  14.     printf("Input 除数:");
  15.     scanf("%d", &b);
  16.     
  17.     k = strlen(a1);
  18.     for(i = 0; i < k; i++)
  19.         a[i] = a1[k - i - 1] - '0'; //将被除数倒序变为int型存放
  20.     
  21.     for(i = k - 1; i >= 0 ; i--)
  22.     {
  23.         d = d * 10 + a[i];
  24.         c[i] = d / b;
  25.         d = d % b;
  26.     }
  27.     while(c[k - 1] == 0 && k > 1) k--;
  28.     printf("商=");
  29.     for(i = k - 1; i >= 0; i--) printf("%d", c[i]);
  30.     printf("\n余数=%d", d);
  31.     return 0;
  32. }


《算法竞赛入门经典》
P28      2.4.2浮点数陷阱

 

  1. #include <stdio.h>
  2. int main ()
  3. {
  4.     double i;
  5.     for (i=0;i!=10;i+=0.1)
  6.         printf("%.1lf\n",i);
  7.     return 0;
  8. }


下面应用网上大神的分析:

浮点数陷阱:

       该程序的运行结果是:  无限循环.

   之所以无限循环,那么就可以推断是for循环的条件始终成立,即 i 始终不等于10.

   但是 i 是从0开始的,每次都自加0.1.那么应该是100次后就停止.为什么i始终不

   等于10呢? 是因为浮点数的原因. 我们把10改成10.0,结果仍然是无限循环.

   我们把 i += 0.1 改成 i++,发现执行10次后正常停止.我们可以初步推断,是浮点数

   的加法运算引起的.

   接下来调用gdb输出中间结果来观察,发现 i 自加0.1后,并不是我们预想的等于0.1

   而是等于 0.10000000000000001.

   再往下执行几次,i 的值分别是0.20000000000000001.

                                          0.30000000000000004.      

                                          0.40000000000000002.

       这样,我们就理解了为什么i 始终不等于10. 因为浮点数在进行小数运算的时候由于

   精度问题,会有很小的误差,然而用 = 或者 != 这样的运算符来比较,是会检测出这种

   误差的.所以导致结果的不正确. 

   我们还可以多测试一下,将循环条件改为 i != 0.1 或者 i != 0.2时,程序能够正常

   运行,得到正常结果.但是当i != 0.3时,就是无限循环.显然,在我们的程序中,这种

   不确定的错误是不应该存在的.

   因此,在定义循环变量时,尽量采用int型及整数的加减.因为循环的本质意义就是通过

   各种条件来控制语句重复运行次数.而这个次数本身就是整数.要实现小数的功能尽量

   通过循环中的语句来实现


P32习题2-8
本题计算过程中需要计算1除以正整数m的平方,而m的取值是小于10的6次方
如果代码写作1/pow(m,2)会出现精度不足的问题
写作1/m/m则每一步计算都在浮点型精度内。



P32习题2-9
题设:     输入正整数a,b,c 输出a/b的小数形式,精确到小数点后c位。a,b小于等于10的6次方,c小于100.
本题先引用网上流传的解法,虽然错的比较离谱,但有些学习的价值

 

  1. #include<stdio.h>
  2. int main()
  3. {
  4.   int a,b,c;
  5.   scanf("%d%d%d",&a,&b,&c);
  6.   printf("%.*lf",c,(double)a/b);
  7.   return 0;
  8. }

  9. /* 分析: 该题间接地给我们提供了printf的一种很强大的使用方法,

  10.       即通过变量来控制精度.我们一般在使用printf进行格式控制的时候,都是按照

  11.      给定的精度进行控制,比如精确到小数点后三位.而使用变量来控制精度呢?

  12.      在printf中可以使用类似于通配符的*来实现.

  13.      符号*是用后面参数表给出的变量进行替代.因此,%.*lf可通过与*对应的变量

  14.      来控制小数点后的位数. */

上述解法的弊端在于当c较大,例如c=20,double型变量的精度不足。

下面我自己的提供两个思路

 

  1. //《算法竞赛入门经典》P32习题2-9“循环除”法 2012/7/19

  2. #include <stdio.h>
  3. #include <stdlib.h>

  4. int main ()
  5. {
  6.     int a,b,c,i,temp;
  7.     scanf("%d%d%d",&a,&b,&c);
  8.     temp=a/b;
  9.     printf("%d.",temp); //输出整数部分及小数点
  10.     for (i=0;i<c;i++)
  11.     {
  12.         a=a%b*10;
  13.         temp=a/b;
  14.         printf("%d",temp);
  15.     }
  16.     system("pause");
  17.     return 0;
  18. }

 

  1. //《算法竞赛入门经典》P32习题2-9 利用高精度除以低精度的算法

  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>

  5. int main()
  6. {
  7.     int a,b,c,k,i,temp,str1[120],str2[120];
  8.     char ch[10];
  9.     scanf("%d%d%d",&a,&b,&c);
  10.     memset(str1,0,sizeof(int)*120); //将存储数组全部置0
  11.     memset(str2,0,sizeof(int)*120);
  12.     temp=a%b; //用temp存储余数部分
  13.     itoa(temp,ch,10);
  14.     k=strlen(ch); //用k记录余数长度

  15.     for (i=0;ch[i]!=0;i++)
  16.         str1[i]=ch[i]-'0';

  17.     for (i=1,temp=str1[0];i<c+k;i++)
  18.     {
  19.         temp=temp*10+str1[i];
  20.         str2[i-1]=temp/b;
  21.         temp%=b;
  22.     }

  23.     while(str2[k-1]==0 && k>1) //排除多余的0
  24.         k--;

  25.     printf("%d.",a/b); //输出整数部分与小数点

  26.     for (i=k-1;i<c+k-1;i++)
  27.         printf("%d",str2[i]);
  28.     printf("\n");
  29.     system("pause");
  30.     return 0;
  31. }


习题2-10
题目描述:用1,2,3,...,9组成3个三位数abc,def和ghi,每个数字恰好使用一次,要求abc:def:ghi=1:2:3.输出所有解。提示:不必太动脑筋。 

本题在提供的每一个算法中都使用了计时函数,用于比较效率,结果第一种最慢,后两种因时间精度不足无法比较。

先提供网上流传的直接解法,看得我一阵腹痛。。。


 

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>

  4. int main ()
  5. {
  6.     int a,b,c,d,e,f,g,h,i;
  7.     for (a=1; a<=3; a=a+1)
  8.        for (b=1; b<=9; b=b+1)
  9.            if (b!=a)
  10.               for (c=1; c<=9; c=c+1)
  11.                   if (c!=a && c!=b)
  12.                      for (d=a*2; d<=9; d=d+1)
  13.                          if (d!=a && d!=b && d!=c)
  14.                             for (e=1; e<=9; e=e+1)
  15.                                 if (e!=a && e!=b && e!=c && e!=d)
  16.                                    for (f=1; f<=9; f=f+1)
  17.                                        if (f!=a && f!=b && f!=c && f!=d && f!=e)
  18.                                           for (g=a*3; g<=9; g=g+1)
  19.                                               if (g!=a && g!=b && g!=c && g!=d && g!=e && g!=f)
  20.                                                  for (h=1; h<=9; h=h+1)
  21.                                                      if (h!=a && h!=b && h!=c && h!=d && h!=e && h!=f && h!=g)
  22.                                                         for (i=1; i<=9; i=i+1)
  23.                                                             if (i!=a && i!=b && i!=c && i!=d && i!=e && i!=f && i!=g && i!=h &&
  24.                                                                (a*100+b*10+c)*2==d*100+e*10+f &&
  25.                                                                (a*100+b*10+c)*3==g*100+h*10+i)
  26.                                                                printf("%d%d%d, %d%d%d, %d%d%d\n",a,b,c,d,e,f,g,h,i);
  27.                                                         
  28.     printf("Time used = %.3lf\n",(double)clock()/CLOCKS_PER_SEC);
  29.     system("pause");
  30.     return 0;
  31. }

下面列出根据不同思路写的两种算法


 

  1. /*1~9组成的最小三位数是123,最大的是987,由于要满足1:2:3的关系,最小的那个数应该不到于987/3=329。这样的话第一个数的变化范围是123~329,将这里面的数分别乘2、乘3,然后判断这三个数是否符合要求,即这三个数是否由1~9组成,而且各个数字不能相同。
  2.      即对每个数n(123<=n<=329)用枚举法。
  3. */


  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <time.h>

  7. int judge (int n);

  8. int main ()
  9. {
  10.     int k,m,n,p,q;
  11.     for(k=123;k<=329;k++)
  12.     {
  13.         m=2*k;
  14.         n=3*k;
  15.         p=k*1000+m;
  16.         q=p*1000+n;
  17.         if(judge(q)) //判断k,m,n是否符合要求。如果不符合就跳出本次循环,进入下次循环
  18.             printf("%d,%d,%d\n",k,m,n);
  19.         else continue;
  20.     }
  21.     printf("Time used = %.3lf\n",(double)clock()/CLOCKS_PER_SEC);
  22.     system("pause");
  23.     return 0;
  24. }

  25. int judge (int n)
  26. {
  27.     int a[9],i,j;
  28.     for (i=0;i<9;i++)
  29.     {
  30.         if ((a[i]=n%10)==0)
  31.             return 0;
  32.         n/=10;
  33.     }
  34.     for (i=0;i<9;i++)
  35.         for (j=i+1;j<9;j++)
  36.             if (a[i]==a[j])
  37.                 return 0;
  38.     return 1;
  39. }

 

  1. //利用1-9的和为45,乘积为362880判断

  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <time.h>

  5. int judge (int a,int b,int c);

  6. int main()
  7. {
  8.     int i;
  9.     for (i=111;i<329;i++)
  10.        if (judge(i,2*i,3*i))
  11.            printf("%d %d %d\n",i,2*i,3*i);
  12.     printf("Time used = %.3lf\n",(double)clock()/CLOCKS_PER_SEC);
  13.     system("pause");
  14.     return 0;
  15. }


  16. int judge (int a,int b,int c)
  17. {
  18.     int i,sum=0,pro=1,str[9];
  19.     str[0] = a / 100;
  20.     str[1] = a / 10 % 10;
  21.     str[2] = a % 10;
  22.     str[3] = b / 100;
  23.     str[4] = b / 10 % 10;
  24.     str[5] = b % 10;
  25.     str[6] = c / 100;
  26.     str[7] = c / 10 % 10;
  27.     str[8] = c % 10;
  28.     for (i=0;i<9;i++)
  29.     {
  30.         sum+=str[i];
  31.         pro*=str[i];
  32.     }
  33.     if (sum==45 && pro==362880)
  34.         return 1;
  35.     else return 0;
  36. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值