hdu1058 Humble Numbers

 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 */

 

posted @ 2013-01-19 22:35  kiwi_bird  阅读(159)  评论(0编辑  收藏  举报