1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 using namespace std;
5 const int MAXN = 2000000000;
6
7 bool vis[32][21][15][13];
8 int f2[32]={1},f3[21]={1},f5[15]={1},f7[13]={1};
9 int dd[6000],cnt;
10
11 void dp(int a,int b,int c,int d,long long x)
12 {
13 if( vis[a][b][c][d] ) return ;
14 if( x>MAXN ) return ;
15 vis[a][b][c][d]=true;
16 dp(a,b,c,d+1,x*7);
17 dp(a,b,c+1,d,x*5);
18 dp(a,b+1,c,d,x*3);
19 dp(a+1,b,c,d,x*2);
20 }
21
22 int main()
23 {
24 int n;
25 memset(vis,false,sizeof(vis));
26 dp(0,0,0,0,1);
27 cnt=0;
28 for(int i=1;i<32;i++) f2[i]=f2[i-1]*2;
29 for(int i=1;i<21;i++) f3[i]=f3[i-1]*3;
30 for(int i=1;i<15;i++) f5[i]=f5[i-1]*5;
31 for(int i=1;i<13;i++) f7[i]=f7[i-1]*7;
32 for(int a=0;a<32;a++)
33 for(int b=0;b<21;b++)
34 for(int c=0;c<15;c++)
35 for(int d=0;d<13;d++)
36 if( vis[a][b][c][d] )
37 dd[++cnt]=f2[a]*f3[b]*f5[c]*f7[d];
38 sort(dd+1,dd+cnt+1);
39 while( scanf("%d",&n),n )
40 {
41 int r=n%10,t=n%100;
42 if( 11==t || 12==t || 13==t ) printf("The %dth humble number is %d.\n",n,dd[n]);
43 else if( 1==r ) printf("The %dst humble number is %d.\n",n,dd[n]);
44 else if( 2==r ) printf("The %dnd humble number is %d.\n",n,dd[n]);
45 else if( 3==r ) printf("The %drd humble number is %d.\n",n,dd[n]);
46 else printf("The %dth humble number is %d.\n",n,dd[n]);
47 }
48 return 0;
49 }
50 /*
51 ①
52 丑数可以写成2^a * 3^b * 5^c * 7^d的形式。
53 由1开始,依次乘2,3,5,7,生成以后的丑数。
54 这样的生成结果并不就是按照大小顺序的。
55 就一直生成,直到在maxn(幸亏题目给了这个数,嘻嘻)范围内没有新的丑数生成为止。
56 生成过程中,存在大量重复,如2*3=6,3*2=6就是一个重复。
57 这里用了DP的思想,已经走过的路就不再走了。
58 vis[a][b][c][d]记录状态,分别表示2^a * 3^b * 5^c * 7^d这个数字是否生成过。
59 总状态数小于32*21*15*13,状态转移是再考察由这个数生成的4个数,复杂度约50万。
60 又觉得这里没有状态转移,因为这个状态和由它生成的状态没有关系,不知道最优子结构体现在哪里,其实就是记忆化搜索。
61 但是本质又觉得是一样的。都是利用状态来记忆化。
62 ②
63 巧妙的构造法:(觉得和two-pointer有点像)
64 每次按顺序生成第i个丑数,复杂度为O(n),不用利用maxn那个值。但感觉这两个算法的时间差不多。。。
65 更新i,j,k,l四个值
66 初始,i=j=k=l=1,f[1]=1;
67 f[n]=min(f[i]*2,f[j]*3,f[k]*5,f[l]*7)
68 if( f[n]==f[i]*2 ) i++;
69 if( f[n]==f[j]*3 ) j++;
70 if( f[n]==f[k]*5 ) k++;
71 if( f[n]==f[l]*7 ) l++;
72 直至n>5842
73 大体可以验证这个算法的正确性,
74 f[2]=min(f[1]*2,f[1]*3,f[1]*5,f[1]*7)=f[1]*2;
75 之后的丑数可以分为这么几类:*2型(f[2]*2最小),*3型(f[1]*3最小),*5型(f[1]*5最小),*7型(f[1]*7最小),
76 那么下一个丑数就是min(f[2]*2,f[1]*3,f[1]*5,f[1]*7),之后同理。
77 ③
78 利用set容器(排序加去重)打表
79 */