zoukankan      html  css  js  c++  java
  • 寻找丑数问题 HDOJ 1058 Humble Numbers

    这是题目描述。

    这道题目曾经也是Google、Hulu的一道面试题。对于这道题目,关键是要能够想到这一点:即对于任意一个丑数f[i],它都是由它前面的丑数乘以2,3,5或者7得到的。那么如果我们已经得到f[0] 到 f[i],怎样才能得到f[i+1]呢? 

    可能你会怎么想(我刚开始也是这么想的)。我们已经有第一个丑数f[1] = 1,那么就设一个游标i=1指向f[1],然后依次将2,3,5,7与f[i]相乘,即我们可以得到2,3,5,7,然后依次将这些丑数加入到f[i]中,f[2] = 2, f[3] = 3, f[4] = 5, f[5] = 7,接着讲游标i++指向2,再分别于2,3,5,7相乘,即可以得到f[6] = 4, f[7] = 6, f[8] = 10, f[9] = 14。按照这种算法算下去,直到丑数的个数累计到了5842个。 仔细再想,我们会发现这种算法有两个问题,第一:所得的丑数数组是乱序的,即我们还需要对其进行排序,不过这个问题不大;更为严重的问题是数组中存在重复的丑数:前面我们已经得到了f[7] = 6,如果按以上算法继续算下去的话,很容易我们也可以得到f[10] = f[3] * 2= 6.所以我们排序完成之后要将数组中重复的数组去掉,去除完了之后又要进行新一轮的迭代,来使丑数数组中的不重复丑数达到5842个以上,很显然这个是很难用程序去控制的,因为我们需要事先计算出数组到底有多少重复的丑数,不过按照这个规律的话应该是可以算出来,不过我还没想到怎么算。^_^

    那么有更好的解决方案吗? 这里给出了一个比较好的解决办法。 :

    即定义四个游标,我们记为pos1,pos2,pos3,pos4 ,初始均为1. 这四个游标分别跟踪着对应的丑数乘以2,3,5,7所得的值。我们已经看到了方法一会给我们带来乱序和丑数重复的问题,方法二可以很好地解决这两个问题。 我们由一中的分析已经得到了f[i+1]是由f[1]到f[i]中的某个数乘以2,3,5,7中的某个数得来的。具体解法见以下代码,需要注意的是,arr[i]中可能会有两个同样的值是最小的,下面这小段代码解决了方法一中遇到的丑数重复的问题。

    1. <span style="white-space:pre">        </span>for(int j=0; j<N; j++)  
    2.             if(flag[j])  
    3.                 pos[j]++;  

    对其进行了简单的修改,当然解题思想是参考该作者的。

      1. #include<iostream>  
      2. #include<string>  
      3. using namespace std;  
      4.   
      5. int const N = 4;  
      6. int map[N] = {2,3,5,7};  
      7.   
      8. int findMin(int arr[], bool flag[], int len)  
      9. {  
      10.     int min = arr[0];  
      11.     int i=0;  
      12.     for(i=0; i<len; i++)  
      13.         if(arr[i] < min)  
      14.             min = arr[i];  
      15.     for(i=0; i<len; i++)  
      16.     {  
      17.         if(min == arr[i])  
      18.             flag[i] = true;  
      19.         else  
      20.             flag[i] = false;  
      21.     }  
      22.       
      23.     return min;  
      24. }  
      25.   
      26.   
      27. void initHumble(int maxN, int humble[])  
      28. {  
      29.     humble[1] = 1;  
      30.     int pos[N] = {1,1,1,1};  
      31.     int arr[N];  
      32.     bool flag[N];  
      33.   
      34.     for(int i=2; i<=maxN; i++)  
      35.     {  
      36.   
      37.         for(int j=0; j<N; j++)  
      38.             arr[j] = humble[pos[j]]*map[j];  
      39.   
      40.         int min = findMin(arr, flag, N);  
      41.         humble[i] = min;  
      42.         for(int j=0; j<N; j++)  
      43.             if(flag[j]) //相同的最小丑数在这里会被过滤掉  
      44.                 pos[j]++;  
      45.           
      46.     }  
      47. }  
      48.   
      49. void outPut(int humble[])  
      50. {  
      51.     int n;  
      52.   
      53.     while(cin>>n && n)  
      54.     {  
      55.         string str = "th";  
      56.         if(n%10==1 && n%100!=11)  
      57.             str = "st";  
      58.         else if(n%10==2 && n%100!=12)  
      59.             str = "nd";  
      60.         else if(n%10==3 && n%100!=13)  
      61.             str = "rd";  
      62.   
      63.         cout<<"The "<<n<<str<<" humble number is "<<humble[n]<<"."<<endl;  
      64.     }  
      65. }  
      66.   
      67. int main()  
      68. {  
      69.     const int SIZE = 6000;  
      70.   
      71.     int humble[SIZE];  
      72.   
      73.     initHumble(5842, humble);  
      74.       
      75.     outPut(humble);  
      76.   
      77.     return 0;  
      78. }  
    多学习,多总结。
  • 相关阅读:
    COGS 2104. [NOIP2015]神奇的幻方
    洛谷 P1387 最大正方形
    包和一些常用的模块
    模块
    模块的导入和使用
    函数迭代器与生成器
    函数的小知识
    函数的闭包和装饰器
    函数的进阶
    初识函数
  • 原文地址:https://www.cnblogs.com/yanhaiming/p/2580846.html
Copyright © 2011-2022 走看看