• 《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)


    原题及翻译

    For a positive integer N , the digit-sum of N is defined as the sum of N itself and its digits.
    对于正整数n,n的位数和定义为n本身及其位数的和。
    When M is the digitsum of N , we call N a generator of M .
    当M是n的位数,我们称n为m的生成器。
    For example, the digit-sum of 245 is 256 (= 245 + 2 + 4 + 5).
    例如,245的数字和为256(=245+2+4+5)。
    Therefore, 245 is a generator of256.
    因此,245是256的生成器。
    Not surprisingly, some numbers do not have any generators and some numbers have more than one generator.
    不足为奇,有些数字没有任何生成器,有些数字有多个生成器。
    For example, the generators of 216 are 198 and 207.
    例如,216的生成器是198和207。
    You are to write a program to find the smallest generator of the given integer.
    您要编写一个程序来查找给定整数的最小生成器。

    Input

    输入
    Your program is to read from standard input.
    您的程序将从标准输入中读取。
    The input consists of T test cases.
    输入由T测试用例组成。
    The number of test cases T is given in the first line of the input.
    测试用例数t在输入的第一行给出。
    Each test case takes one line containing an integer N , 1 ≤ N ≤ 100, 000.
    每个测试用例取一行,包含一个整数n,1≤n≤100000。

    Output

    输出
    Your program is to write to standard output.
    您的程序将写入标准输出。
    Print exactly one line for each test case.
    每个测试用例只打印一行。
    The line is to contain a generator of N for each test case.
    对于每个测试用例,该行包含一个n的生成器。
    If N has multiple generators, print the smallest.
    如果n有多个生成器,请打印最小的。
    If N does not have any generators, print ‘0’.
    如果n没有任何生成器,请打印“0”。

    Sample Input

    3
    216
    121
    2005

    Sample Output

    198
    0
    1979

    思路

    1.第一个想到的就是,暴力枚举,一开始写的是六层循环,作死的节奏,结果肯定是超时的,然后再把循环层数减到两层,从1枚举到最大值,但是每次枚举都要与n个数判断是否符合条件,时间复杂度O(n2),还是会超时,只有把时间复杂度降到O(n),才能AC。

    2.枚举也有两种方法,第一种就是将1~ max枚举然后分别判断,第二种是将1~ 100000的所有生成元与其数字对应,没有生成元的就标为0,然后分别输入数字将其对应的生成元输出。

    代码分析

    先把超时的代码放出来,算法很简单,很好理解,但是,超时,不管怎样,没AC就是WA。

    #include <stdio.h>
    #include <string.h>
    int main ()
    {
     int n,max=0;
     scanf("%d",&n);
     int m[n];
     for(int i=0;i<n;i++)
     {
      scanf("%d",&m[i]);
      if(m[i]>max) max=m[i];
     }
     int x[n],flag[n],index=0;
     memset(x,0,sizeof(x));
     memset(flag,0,sizeof(flag));
     for(int i=1;i<=max;i++)
     {
      int a=i/100000%10,b=i/10000%10,c=i/1000%10,d=i/100%10,e=i/10%10,f=i/1%10;
      for(int j=index;j<n;j++)
      {
          if(a*100000+b*10000+c*1000+d*100+e*10+f+a+b+c+d+e+f==m[j])
       {
           x[j]=a*100000+b*10000+c*1000+d*100+e*10+f;flag[j]=1;index++;
       }
      }
     }
     for(int i=0;i<n;i++)
     {
          if(flag[i]==0) printf("0 \n");
       else printf("%d \n",x[i]);
     }
     return 0;
    }
    

    接下来看正确的结果:
    1.创建一个全局变量的数组将从1~100000的所有生成元存储起来:

    #define max 100000
    int ans[max];
    

    2.计算生成元并存储:

     for(int m=1;m<max;m++)
     {//从1开始遍历
      int x=m,y=m;
      //x,y作为计算生成元的中间变量
      while(x>0)
      {//将y分别与x的每一位相加,即生成元
       y+=x%10;
       x/=10;
      }
      if(ans[y]==0||ans[y]>m) ans[y]=m;
      //将即将输入的数字y与其生成元m对应
     }
    

    完整代码

    #include <stdio.h>
    #include <string.h>
    #define max 100000
    int ans[max];
    int main()
    {
     int t,n;
     memset(ans,0,sizeof(ans));
     for(int m=1;m<max;m++)
     {
      int x=m,y=m;
      while(x>0)
      {
       y+=x%10;
       x/=10;
      }
      if(ans[y]==0||ans[y]>m) ans[y]=m;
     }
     scanf("%d",&t);
     while(t--)
     {
      scanf("%d",&n);
      printf("%d\n",ans[n]);
     }
     return 0;
    }
    

    每天磕一道ACM 正月初三打卡

  • 相关阅读:
    JVM运行时数据区与JVM堆内存模型小结
    Java Management Extensions (JMX)
    ubuntu 中 搭建 C编程环境
    个人使用的电脑软件
    Navicat Premium 12 安装 与 激活
    利用 canvas 实现压缩图片
    barcode模块: plus.barcode.scan 进行扫描图片出现无法识别二维码,打印的错误信息是code:8,message:''
    win10 出现 No AMD graphics driver is installed or the AMD driver is not functioning properly .....
    H5项目 使用Cropper.js 实现图片 裁剪 操作 (APP端)
    Java 正则表达式获取两个字符中间的内容
  • 原文地址:https://www.cnblogs.com/AlexKing007/p/12339531.html
Copyright © 2020-2023  润新知