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