Problem
acm.hdu.edu.cn/showproblem.php?pid=1058
题意
找出从小到大第 n 个因子(除了 1 和本身)只有 2、3、5、7 的数。即第 n 个 num = 2^a * 3^b * 5^c * 7^d 的数(据说叫丑数)。
分析
从 1 开始,乘2、3、5、7中的随便一个,就产生 4 个这样的数;从这 4 个数出发,分别乘 2、3、5、7,再产生更多的数…依此类推产生所有这样的数。
但要从小到大排序。可以想出,下一个最小的丑数肯定是某几个之前的丑数乘 2 或 3 或 5 或 7 产生的。
按上面的产生方法,每丑数乘 2 可以产生新的一个新的丑数,其它也是。
将丑数按升序存在一个数组 ugly [] 里,用 4 个变量 a、b、c、d 分别记录一个下标,表示 2、3、5、7 下一次要跟哪个之前的丑数相乘产生新丑数。
产生的 4 个新丑数就是:2 * ugly[a]、3 * ugly[b]、5 * ugly[c]、7 * ugly[d]。它们是可能的下一个最小的丑数。
从它们之间找那个最小的加到数组尾,然后判断是由哪个因子产生的,让它的下标加一(指向下一个还没跟它相乘产生新丑数的丑数)。
它们这些产生的新丑数中,可能有重复,所以可能一次要移动多个下标。
Source code
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 5842;
int ugly[N+1] = {0, 1};
int main()
{
for(int i=2,two=1,three=1,five=1,seven=1; i<=N; ++i)
{
ugly[i] = min(
min(2 * ugly[two], 3 * ugly[three]),
min(5 * ugly[five], 7 * ugly[seven])
);
// 可能新丑数有重复,不能加 else
if(ugly[i] == 2 * ugly[two])
++two;
if(ugly[i] == 3 * ugly[three])
++three;
if(ugly[i] == 5 * ugly[five])
++five;
if(ugly[i] == 7 * ugly[seven])
++seven;
}
for(int n; scanf("%d", &n), n; )
{
printf("The %d", n);
if(n % 10 == 1 && n % 100 != 11)
printf("st");
else if(n % 10 == 2 && n % 100 != 12)
printf("nd");
else if(n % 10 == 3 && n % 100 != 13)
printf("rd");
else
printf("th");
printf(" humble number is %d.\n", ugly[n]);
}
return 0;
}
这居然是 dp…看来我对 dp 的理解还是太肤浅