I am a teacher!

导航

C语言程序设计100例之(61):数字对

例61   数字对

问题描述

对于一个数字对(a, b),我们可以通过一次操作将其变为新数字对(a+b, b)或(a, a+b)。

给定一正整数n,问最少需要多少次操作可将数字对(1, 1)变为一个数字对,该数字对至少有一个数字为n。

输入

第一行一个正整数 n(1 <= n <= 106)。

输出

一个整数表示答案。

输入样例

5

输出样例

3

样例解释

(1,1)  →  (1,2)  →  (3,2)  →  (5,2)

        (1)编程思路。

        设函数int calc(int a,int b)的返回值是将数字对 (a,b)(不妨设a>b)还原为(1,1)所需的最少操作次数。

        显然,若b==1,则calc(a,b)的值为a-1;若b==0,则不可能还原为(1,1),其返回值设定为INF(一个尽可能大的正整数)。

        为了加速(a,b)还原为(1,1),不用每次从a中减去1个b,可以采用类似辗转相除法的思想,用a/b次操作将其还原为(b,a%b)。

        按上面的思路,将函数int calc(int a,int b)写成递归函数。

        求出函数值calc(n,1)、calc(n,2)、calc(n,3)、…、calc(n,n-1)中的最小值,即是求得的最少操作次数。

(2)源程序。

#include <stdio.h>

#define INF 0x3fffffff

int calc(int a,int b)

{

    if (b==1) return a-1;

    if (!b) return INF;

    return a/b+calc(b,a%b);

}

int main()

{

    int n,ans;

    scanf("%d",&n);

    ans=n-1;

    int i;

    for (i=1;i<n;i++)

    {

        int t=calc(n,i);

        if (t<ans) ans=t;

    }

    printf("%d",ans);

    return 0;

}

习题61

61-1  分解因数

问题描述

给出一个正整数a,要求分解成若干个正整数的乘积,即a = a1 * a2 * a3 * ... * an,并且1 < a1 <= a2 <= a3 <= ... <= an,问这样的分解的种数有多少。注意到a = a也是一种分解。

输入

第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数a (1 < a < 32768)。

输出

n行,每行输出对应一个输入。输出应是一个正整数,指明满足要求的分解的种数。

输入样例

2

2

20

输出样例

1

4

         (1)编程思路。

        设函数fun(int a,int n)表示从a开始对n进行因式分解。显然,可以用循环

         for  (i=a;i<=sqrt(n);i++) 来分解n的每一个约数,

         若n%i==0,表示i是n的一个约数,i*(n/i)就是一个满足要求的分解式,计数count++,之后继续对n/i进行分解,即可以递归调用fun(i,n/i)。

       (2)源程序。

#include<stdio.h>

int count;

void  fun(int a,int n)

{

       int i=n,j;

       for(i=a;i<n;i++)

       {

              if(n%i==0 && i<=n/i)

              {

                     count++;

                     fun(i,n/i);      

              }

              if(i>n/i)   break;

       }

}

int main()

{

       int n,m,i;

       scanf("%d",&n);

       for(i=0;i<n;i++)

       {

              scanf("%d",&m);

              count=1;     // m=m也是一种分解

              fun(2,m);

              printf("%d\n",count);

       }

      return 0;

}

61-2  波兰表达式

问题描述

波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的波兰表示法为+ 2 3。波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的波兰表示法为* + 2 3 4。本题求解波兰表达式的值,其中运算符包括+ - * /四个。

输入

输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数。

输出

输出为一行,表达式的值。

输入样例

* + 11.0 12.0 + 24.0 35.0

输出样例

1357.000000

       (1)编程思路。

        根据波兰表达式的定义进行递归求解。在递归函数中,针对当前的输入,有五种情况:

        1)输入是运算数,则表达式的值就是这个运算数;

        2)输入是’+’,则表达式的值是再继续读入两个表达式并计算出它们的值,然后将它们的值相加;

        3)输入是’-’,则表达式的值是再继续读入两个表达式并计算出它们的值,然后将它们的值相减;

        4)输入是’*’,则表达式的值是再继续读入两个表达式并计算出它们的值,然后将它们的值相乘;

        5)输入是’/’,则表达式的值是再继续读入两个表达式并计算出它们的值,然后将它们的值相除。

       (2)源程序。

#include <stdio.h>

#include <stdlib.h>

double fun(void)

{

    char a[10];

    double t;

    scanf("%s", a);

    switch(a[0])

    {

        case'+': return fun() + fun();

        case'-': return fun() - fun();

        case'*': return fun() * fun();

        case'/': return fun() / fun();

        default: t=atof(a);

               return t;

     }

}

int main()

{

     double ans;

     ans = fun();

     printf("%f\n", ans);

     return 0;

}

61-3  四舍五入

问题描述

对于给定的数字,如果大于10,将其四舍五入到最接近的10,然后(如果结果大于100)将结果四舍五入到最接近的100,然后(如果结果大于1000)将该数字四舍五入到最接近的1000,…,依此类推。

输入

输入第1行包含一个整数n,表示要舍入的整数个数。

接下来的n行各包含一个整数x(0<=x<=9999999)。

输出

对于输入中的每个整数,在一行中显示取整的整数。

输入样例

9

15

14

4

5

99

12345678

44444445

1445

446

输出样例

20

10

4

5

100

10000000

50000000

2000

500

         (1)编程思路。

        设函数int rounders(int a,int b) 功能是将整数a四舍五入到最接近的b。可以编写成简单的递归函数。参见源程序。

        为了方便对这个递归函数的理解,下面以样例中1445的计算为例进行说明。

        1445的四舍五入从个位开始,调用函数rounders(1445,10),因为1445%10>=10/2,所以个位的5向前进位,即(1445/10+1)*10=1450;再对1450的十位进行四舍五入,递归调用rounders(1450,100),因为1450%100>=100/2,所以十位的5向前进位,即(1450/100+1)*100=1500;再对1500的百位进行四舍五入,递归调用rounders(1500,1000),因为1500%1000>=1000/2,所以百位的5向前进位,即(1500/1000+1)*1000=2000;再对2000的千位进行处理,递归调用rounders(2000,10000),因为2000<10000,递归调用结束,最终返回结果为2000。

        再以样例中12345678的计算为例进行说明。

        12345678的四舍五入从个位开始,调用函数rounders(12345678,10),因为12345678%10=8>=10/2,所以个位的8向前进位,即(12345678/10+1)*10=12345680;再对12345680的十位进行四舍五入,递归调用rounders(12345680,100),因为12345680%100=80>=100/2,所以十位的8向前进位,即(12345680/100+1)*100=12345700;再对12345700的百位进行四舍五入,递归调用rounders(12345700,1000),因为12345700%1000=700>=1000/2,所以百位的7向前进位,即(12345700/1000+1)*1000=12346000;再对12346000的千位进行处理,递归调用rounders(12346000,10000),因为12346000%10000=6000>=10000/2,所以千位的6向前进位,即(12346000/10000+1)*10000=12350000;再对12350000的万位进行处理,递归调用rounders(12350000,100000),因为12350000%100000=50000>=100000/2,所以万位的5向前进位,即(12350000/100000+1)*100000=12400000;再对12400000的十万位进行处理,递归调用rounders(12400000,1000000),因为12400000%1000000=400000<1000000/2,所以十万位的4舍去不向前进位,即(12400000/1000000+1)*1000000=12000000;再对12000000的百万位进行处理,递归调用rounders(12000000,10000000),因为12000000%10000000=2000000<10000000/2,所以百万位的2舍去不向前进位,即(12000000/10000000+1)*10000000=10000000;再对10000000的千万位进行处理,递归调用rounders(10000000,100000000),因为10000000<100000000,递归调用结束,最终返回结果为10000000。

        (2)源程序。

#include<stdio.h>

int rounders(int a,int b)

{

    if (a<=b) return a;

    if (a%b<b/2) return rounders((a/b)*b,b*10);  // 四舍

    return rounders((a/b+1)*b,b*10);           // 五入

}

int main()

{

    int n;

    scanf("%d",&n);

    while (n--)

    {

       int x;

       scanf("%d",&x);

       printf("%d\n",rounders(x,10));

    }

    return 0;

}

posted on 2022-01-27 10:27  aTeacher  阅读(474)  评论(0编辑  收藏  举报