humble number——二分查找与哈希表拉链法

Humble Numbers丑数

对于一给定的素数集合 S = {p1, p2, ..., pK}, 来考虑那些质因数全部属于S 的数的集合。这个集合包括,p1, p1p2, p1p1, 和 p1p2p3 (还有其它)。这是个对于一个输入的S的丑数集合。注意:我们不认为1 是一个丑数。

你的工作是对于输入的集合S去寻找集合中的第N个丑数。longint(signed 32-bit)对于程序是足够的。

PROGRAM NAME: humble

INPUT FORMAT

第 1 行:

二个被空间分开的整数:K 和 N , 1<= K<=100 , 1<= N<=100,000.

第 2 行:  

K 个被空间分开的整数:集合S的元素

SAMPLE INPUT (file humble.in)
4 19
2 3 5 7

OUTPUT FORMAT
单独的一行,写上对于输入的S的第N个丑数。

SAMPLE OUTPUT (file humble.out)
27

 

转移方程:f[i]=min{f[k]*a[j]}  1<=k<i,1<=j<=n

即用给定的素数乘以已经生成的丑数得到的积中最小的,时间复杂度为O(n*m),太低效。

优化:s[j]代表素数a[j]乘到的丑数位置,这样转移方程就变为了:

f[i]=min{f[s[j]]*a[j]} 1<=j<=n

时间复杂度为O(n)。

还有一个问题:判重。如果最小值出现过,则跳过,继续找其他里面的最小值,主要可以用

哈希表以及二分查找两种方法。能用二分查找是因为f[i]数组是有序的,如果无序就不能用了。

二分查找判重:

 

 

 

代码
   
     
1 #include < stdio.h >
2 #include < stdlib.h >
3 #include < string .h >
4 int s[ 101 ],a[ 101 ],k,n;
5 long f[ 100001 ],min;
6
7 int check(long x,int low,int high)
8 {
9 int i,j,middle;
10 i = low;j = high;
11 while (i <= j)
12 {
13 middle = (i + j) / 2 ;
14 if (f[middle] == x) return 1 ;
15 else
16 {
17 if (f[middle] < x)i = middle + 1 ;
18 else j = middle - 1 ;
19 }
20 }
21 return 0 ;
22 }
23
24 int main(){
25 FILE * in , * out ;
26 in = fopen( " input6.txt " , " r " );
27 out = fopen( " output.txt " , " w " );
28 fscanf( in , " %d%d " , & n, & k);
29 int i,j,x,j1;
30 for (i = 1 ;i <= n;i ++ )
31 {
32 fscanf( in , " %d " , & a[i]);
33 s[i] = 1 ;
34 }
35
36 f[ 1 ] = 1 ;
37 for (i = 2 ;i <= k + 1 ;i ++ )
38 {
39 min = 2000000000 ;
40 for (j = 1 ;j <= n;j ++ )
41 if (min > f[s[j]] * a[j])
42 {
43 if (check(f[s[j]] * a[j], 2 ,i - 1 ))
44 {
45 s[j] ++ ;
46 j -- ;
47 }
48 else
49 {
50 min = f[s[j]] * a[j];
51 x = j;
52 }
53 }
54 f[i] = min;s[x] ++ ;
55 }
56
57 fprintf( out , " %ld\n " ,f[k + 1 ]);
58 fclose( in );fclose( out );
59 return 0 ;
60 }

哈希表(拉链法,注意红色的代码):

 

代码
   
     
1 #include < stdio.h >
2 #include < stdlib.h >
3 #include < string .h >
4 #include < malloc.h >
5 int s[ 101 ],a[ 101 ],k,n;
6 int f[ 100001 ],min;
7 struct lis
8 {
9 int num;
10 struct lis * next;
11 }list[20000 ];
12
13 int check(int x)
14 {
15 int c;
16 c = x % 20000 ;
17 struct lis * p;
18 if (x == list[c].num) return 1 ;
19 p = list[c].next;
20 while (p != NULL)
21 {
22 if (x == p -> num) return 1 ;
23 p = p -> next;
24 }
25 return 0 ;
26
27 }
28
29 int main(){
30 FILE * in , * out ;
31 in = fopen( " input6.txt " , " r " );
32 out = fopen( " output.txt " , " w " );
33 fscanf( in , " %d%d " , & n, & k);
34 int i,j,x,j1,c;
35 for (i = 1 ;i <= n;i ++ )
36 {
37 fscanf( in , " %d " , & a[i]);
38 s[i] = 1 ;
39 }
40 for (i = 0 ;i < 2000 ;i ++ )
41 {
42 list[i].num = 0 ;
43 list[i].next = NULL;
44 }
45
46 f[ 1 ] = 1 ;
47 for (i = 2 ;i <= k + 1 ;i ++ )
48 {
49 min = 2000000000 ;
50 for (j = 1 ;j <= n;j ++ )
51 if (min > f[s[j]] * a[j])
52 {
53 if (check(f[s[j]] * a[j]))
54 {
55 s[j] ++ ;
56 j -- ;
57 }
58 else
59 {
60 min = f[s[j]] * a[j];
61 x = j;
62 }
63 }
64 f[i] = min;
65 s[x] ++ ;
66 c=min%20000 ;
67 if(list[c].num==0)list[c].num= min;
68 else
69 {
70 struct lis * p;
71 p=(struct lis *)malloc(sizeof(struct lis));
72 p->num= min;
73 p->next= list[c].next;
74 list[c].next= p;
75
76 }
77
78 }
79
80 fprintf( out , " %d\n " ,f[k + 1 ]);
81 fclose( in );fclose( out );
82 return 0 ;
83 }

 

 

 

你可能感兴趣的:(number)