USACO序列一-humble

 

    题目:http://www.nocow.cn/index.php/Translate:USACO/humble

    题目的大意是,给你一些排序的质数,然后要你求出由这些质数作为质因子的第几小的丑数。

    看到这道题的时候,有两种想法,第一种是遍历从最小的丑数开始的自然数,判断这个自然数是不是丑数,直到找到第n个丑数为止。这样做的好处是,想法简单,避免了由质数相乘得到的丑数的排序过程。代码如下:

#include <iostream> #include <fstream> #define MAX 100 using namespace std; int k,n; int s[MAX]; bool humble(int num) { for (int i=0; i < k; i++) { if (num != 1) { while (num % s[i] == 0) { num = num / s[i]; } } else break; } if (num == 1) { return true; } return false; } int main() { ifstream fin("humble.in"); ofstream fout("humble.out"); //输入数据 fin >> k >> n; for (int i =0; i < k; i ++) { fin >> s[i]; } int index = 1; int num; for (num = s[0]+1; index < n; num ++ ) { if (humble(num)) { index ++; } } fout<< num-1 <<endl; return 0; } 
    然而遗憾的是,这个算法的时间复杂度比较高,在TEST 4的时候就通不过了。
    第二种想法是由质数相乘构成丑数,但是构成的丑数的排序始终是一个大问题,但是仔细考虑以后可以发现:
    假设质数集合为{a1,a2,a3……}组成,则丑数集合,
    (1)每一个丑数是由质数本身{a1,a2,a3},或者质数的乘积{a1 * a1, a1 * a2, a1 * a3,……a1 * a2 * a3}。如果我们把1也当成一个丑数,则每一个丑数,可以当做(质数 * 丑数)组成的,如丑数 a1 = 质数 a1 * 丑数 1。丑数 a1 * a2 * a3 = 质数a1 * 丑数(a2 * a3)。因此每一个丑数都可以由前面的丑数递归构造。
    (2)前面也提过新的丑数的排序是一个比较困难的问题,但是由于质数是已经排序好的了,我们能不能构造一个排序好的丑数呢?也就是当我们已知前k个丑数,如何得到第k+1个丑数,使得第k+1个丑数,大于第k个丑数,但是又小于第k+2个丑数。
    为了构造第k+1个丑数,我们针于每个质数p 寻找最小的丑数h,使 h * p满足,比上一个丑数大。取我们找到的 h * p 中最小的一个丑数作为下一个丑数。为了使搜索更快,我们可以为每个质数维护一个索引“pindex”表示每个质数已经乘到了哪个丑数,每次都从那里开始,而不是再从头再来。
     其实仔细想想这个算法跟桶排序算法有异曲同工之妙。桶排序先针对区间进行排序,然后针对区间内进行排序。而这个先对质数进行排序,质数区间内然后由该质数构造的丑数进行排序,保证了由该质数构造的下一个丑数是最小的。然后对k个质数进行排序。从而保证获得的丑数是最小的。
代码如下:
#include <iostream> #include <fstream> #define KMAX 100 #define NMAX 100000 using namespace std; int k,n; int s[KMAX] = {0}; int position[KMAX]={0}; int humble[NMAX]; int length =1; int getNextHumble() { int index = 0; int min = s[0] * humble[position[0]]; if (min <= humble[length-1]) { position[0] ++; min = s[0] * humble[position[0]]; } for (int i=1; i < k; i ++) { int temp = s[i] * humble[position[i]]; if (temp <= humble[length-1]) { position[i] ++; temp = s[i] * humble[position[i]]; } if (temp < min) { min = temp; index = i; }//end temp < min } position[index] ++; return min; } int main() { ifstream fin("humble.in"); ofstream fout("humble.out"); //输入数据 fin >> k >> n; for (int i=0; i < k; i ++) { fin >> s[i]; } humble[0] = 1; for (int i=1; i <=n; i ++) { humble[length] = getNextHumble(); length ++; } fout << humble[length-1]<<endl; return 0; } 

 

你可能感兴趣的:(USACO序列一-humble)