找回密码
 欢迎注册
查看: 58565|回复: 32

[擂台] 求由0和1构成的最小十进制正整数,其是指定正整数的倍数

[复制链接]
发表于 2009-8-11 08:05:11 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?欢迎注册

×
精华
在十进制中,给定正整数N(0 要求: 1、编程环境(包括使用第三方类库)不限; 2、对于任意指定的N或连续的N,尽可能快地输出对应的M。 额外奖励:最先公布出在 08 范围内对应 M 的最大值,经验证无误后,本人将额外转赠100分。 擂台背景:有人在 CSDN 上提出该问题,但截止到目前似乎还没有比较理想的算法,所以放在本论坛里继续讨论;为了方便讨论,特对范围作了下限定。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-8-11 08:20:13 | 显示全部楼层
这是我现在的版本,在输入数据小于32比特时都没有问题,而且速度都很快:
  1. #include <map>
  2. #include <iostream>
  3. #include <ctime>
  4. #include <vector>
  5. #include <math.h>
  6. #include <assert.h>
  7. using namespace std;
  8. typedef long long itype;
  9. typedef map<itype, int> Vmap;
  10. Vmap the_map;
  11. Vmap next_map;
  12. Vmap *cur_map,*prev_map,*tmp_map;
  13. vector<itype> tens;
  14. void dumpvalue(itype key,itype n,int maxbit)
  15. {
  16. Vmap::const_iterator cit;
  17. cit=cur_map->find(key);
  18. assert(cit!=cur_map->end());
  19. int i;
  20. for(i=cit->second;i<maxbit;i++){
  21. cout<<0;
  22. }
  23. cout<<1;
  24. key-=tens[cit->second];
  25. if(key<0)key+=n;
  26. if(key>0){
  27. dumpvalue(key,n,cit->second-1);
  28. }else{
  29. for(i=0;i<cit->second;i++){
  30. cout<<0;
  31. }
  32. }
  33. }
  34. bool cmpit(Vmap::const_iterator it1, Vmap::const_iterator it2,itype n)
  35. {
  36. if(it1->second<it2->second)
  37. return true;
  38. if(it1->second>it2->second)
  39. return false;
  40. itype key1=(it1->first-tens[it1->second]);
  41. itype key2=(it2->first-tens[it2->second]);
  42. if(key1<0)key1+=n;
  43. if(key2<0)key2+=n;
  44. if(key1==0)return true;
  45. if(key2==0)return false;
  46. it1=cur_map->find(key1);
  47. it2=cur_map->find(key2);
  48. return cmpit(it1,it2,n);
  49. }
  50. int main()
  51. {
  52. itype n;
  53. while(1){
  54. cout<<"N=";
  55. cin>>n;
  56. if(n<=0)
  57. break;
  58. clock_t start=clock();
  59. int c2=0,c5=0;
  60. while(n%2==0){c2++;n/=2;}//times of prime 2
  61. while(n%5==0){c5++;n/=5;}//times of prime 5
  62. if(c5<c2)c5=c2;//max times of prime 2 and prime 5
  63. int i;
  64. if(n==1){
  65. cout<<1;
  66. for(i=0;i<c5;i++){cout<<0;}
  67. cout<<endl;
  68. goto output_time;
  69. }
  70. //special case that n+1 is 10^h
  71. itype m=n+1;
  72. int c10=0;
  73. while(m%10==0){m/=10,c10++;}
  74. if(m==1){
  75. for(i=0;i<c10;i++){cout<<111111111;}
  76. for(i=0;i<c5;i++){cout<<0;}
  77. cout<<endl;
  78. goto output_time;
  79. }
  80. int b=(int)sqrt((double)n)+1;
  81. the_map.clear();
  82. tens.clear();
  83. the_map[1]=0;///The first bit 1 is the 0'th bit
  84. cur_map=&the_map;
  85. prev_map=&next_map;
  86. tens.push_back(1);
  87. tens.push_back(10%n);
  88. bool find=false;
  89. itype find_key;
  90. itype mkey;
  91. Vmap::const_iterator bit;
  92. for(i=1;!find;i++){
  93. m=tens[i];
  94. Vmap::iterator it;
  95. Vmap::const_iterator cit;
  96. tmp_map=cur_map;cur_map=prev_map;prev_map=tmp_map;//swap two maps
  97. cur_map->clear();//reset current map
  98. it=prev_map->find(m);
  99. if(it==prev_map->end()){//add when 10^i is new
  100. cur_map->insert(pair<itype,int>(m,i));
  101. }
  102. for(cit=prev_map->begin();cit!=prev_map->end();++cit){
  103. itype key=cit->first;
  104. cur_map->insert(pair<itype,int>(key,cit->second));
  105. key=(key+m)%n;
  106. it=prev_map->find(key);
  107. if(it==prev_map->end()){
  108. cur_map->insert(pair<itype,int>(key,i));
  109. if(key==0){
  110. find_key=key;
  111. find=true;
  112. }
  113. }
  114. }
  115. itype nm=(m*10)%n;
  116. tens.push_back(nm);
  117. if(!find&&cur_map->size()>=b){
  118. nm=n-nm;
  119. itype mink=-1,mkey2;
  120. for(cit=cur_map->begin();cit!=cur_map->end();++cit){
  121. itype nkey=cit->first;
  122. nkey=(itype)((nkey*(long long)nm)%n);
  123. it=cur_map->find(nkey);
  124. if(it!=cur_map->end()){
  125. if(mink==-1||cmpit(cit,bit,n)){
  126. mink=cit->first;
  127. mkey2=nkey;
  128. bit=cit;
  129. }
  130. }
  131. }
  132. if(mink>=0){
  133. find_key=mink;
  134. mkey=mkey2;
  135. find=true;
  136. }
  137. }
  138. }
  139. if(find_key==0){
  140. dumpvalue(0,n,-1);
  141. }else{
  142. dumpvalue(find_key,n,-1);
  143. dumpvalue(mkey,n,i-1);
  144. }
  145. for(i=0;i<c5;i++){cout<<0;}
  146. cout<<endl;
  147. output_time:
  148. clock_t end=clock();
  149. cout<<"Total cost "<<end-start<<"ms"<<endl;
  150. }
  151. return 0;
  152. }
复制代码

评分

参与人数 1威望 +2 收起 理由
winxos + 2 赞.

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-8-11 08:21:58 | 显示全部楼层
至于你那个额外奖励,比较简单 N=99999999 M=111111111111111111111111111111111111111111111111111111111111111111111111

评分

参与人数 1贡献 +3 鲜花 +3 收起 理由
gxqcn + 3 + 3 经验证无误,谢谢!

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-8-11 08:33:44 | 显示全部楼层
看样子 mathe 已对本问题有所研究了。 我抽空把我的一个初步想法实现后再对比看看。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-8-11 19:42:03 | 显示全部楼层
显然,个位必定是1 从个位向高位推吧?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-8-13 10:25:08 | 显示全部楼层

发布我的版本(曾参考了 mathe 的)

我昨天调试了一版,也是通过 map 实现的,但测试下来效率并不高。 于是,潜心研究 mathe 的代码,想到了对自己的一优化算法。 今天,我重新改写算法,结合采用 STL 里的 vector 和 set 容器(不再用 map),测试下来效率非常高 与 2# 同样的,输入数据可为任意小于32比特的正整数。 代码如下:
  1. // http://bbs.emath.ac.cn/viewthread.php?tid=1689&page=1&fromuid=8#pid21060
  2. #include <iostream>
  3. #include <ctime>
  4. #include <vector>
  5. #include <set>
  6. using namespace std;
  7. typedef unsigned int UINT32, *PUINT32;
  8. typedef unsigned __int64 UINT64, *PUINT64;
  9. typedef struct node
  10. {
  11. UINT32 key;
  12. UINT64 value;
  13. }NODE;
  14. typedef vector< NODE > NODE_VECTOR;
  15. typedef set< UINT32 > KEY_SET;
  16. #ifndef UInt32x32To64
  17. # define UInt32x32To64(a, b) (((UINT64)(a)) * (b))
  18. #endif
  19. char szResult[128];
  20. const char * GetMin01( UINT32 n )
  21. {
  22. char * p = szResult;
  23. UINT32 i=0, j=0, d, ten, bits, size;
  24. NODE info;
  25. UINT32 key;
  26. UINT64 value;
  27. NODE_VECTOR vNode;
  28. KEY_SET sKey;
  29. NODE_VECTOR::iterator vIt1, vIt0;
  30. *( p += 127 ) = '\0';
  31. // if ( 0 == n ) return p;
  32. while(0==n%2){++i;n/=2;}//times of prime 2
  33. while(0==n%5){++j;n/=5;}//times of prime 5
  34. if(i<j){i=j;}//max times of prime 2 and prime 5
  35. memset( p -= i, '0', i * sizeof(char));
  36. if ( 1 == n )
  37. {
  38. *(--p) = '1';
  39. return p;
  40. }
  41. //special case that n+1 is 10^j
  42. i = n + 1;
  43. j = 0;
  44. while(0==i%10){i/=10;++j;}
  45. if ( 1 == i )
  46. {
  47. j *= 9;
  48. memset( p -= j, '1', j * sizeof(char));
  49. return p;
  50. }
  51. memset( &info, 0, sizeof( info ));
  52. vNode.push_back( info );
  53. sKey.insert( info.key );
  54. info.value = info.key = 1;
  55. vNode.push_back( info );
  56. sKey.insert( info.key );
  57. for ( bits=1, ten=10%n; ; bits<<=1 )
  58. {
  59. for ( vIt1 = vNode.begin(); vNode.end() != ++vIt1; )
  60. {
  61. key = n - (UINT32)( UInt32x32To64( vIt1->key, ten ) % n );
  62. if ( sKey.end() != sKey.find( key ))
  63. {
  64. for ( vIt0 = vNode.begin(); ++vIt0, key != vIt0->key; )
  65. ;
  66. value = vIt0->value;
  67. do
  68. {
  69. *(--p) = ( 1 & value ) ? '1' : '0';
  70. value >>= 1;
  71. } while( 0 != --bits );
  72. do
  73. {
  74. *(--p) = ( 1 & vIt1->value ) ? '1' : '0';
  75. } while( 0 != ( vIt1->value >>= 1 ));
  76. return p;
  77. }
  78. }
  79. for ( i = 1, size = vNode.size(); size != i; ++i )
  80. {
  81. d = (UINT32)( UInt32x32To64( vNode[i].key, ten ) % n );
  82. value = vNode[i].value << bits;
  83. for ( j = 0; size != j; ++j )
  84. {
  85. key = vNode[j].key;
  86. if (( key += d ) >= n )
  87. {
  88. key -= n;
  89. }
  90. if ( sKey.end() == sKey.find( key ))
  91. {
  92. sKey.insert( info.key = key );
  93. info.value = vNode[j].value | value;
  94. vNode.push_back( info );
  95. }
  96. }
  97. }
  98. ten = (UINT32)( UInt32x32To64( ten, ten ) % n );
  99. }
  100. return p;
  101. }
  102. int main( void )
  103. {
  104. UINT32 n;
  105. const char * p;
  106. while( 1 )
  107. {
  108. cout << "N=";
  109. cin >> n;
  110. if( 0 == n )
  111. {
  112. break;
  113. }
  114. clock_t start=clock();
  115. p = GetMin01( n );
  116. clock_t end=clock();
  117. cout << p << "\n";
  118. cout<< "Total cost " << end-start << "ms" << "\n" << endl;
  119. }
  120. return 0;
  121. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-8-13 11:27:33 | 显示全部楼层
当输入N=4294967291时(32位内的最大素数), 结果为1011101001001001001010000111001, 2# 耗时327ms,6#耗时82ms 其它输入,基本持平,两者各有千秋。 但我的程序在 N=4294967279 时会进入“长考” , 经 debug,发现它将试图构造一个超大的表,暂不知如何解决。 mathe 的程序则可顺利通过,真不知其玄妙在哪里? (其实,mathe 的算法,我主要是阅读 在CSDN 上的描述方面,代码并未细读)
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-8-13 21:14:39 | 显示全部楼层
这个题目要首先考虑控制空间复杂度.
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-8-15 22:18:13 | 显示全部楼层
这几天空闲时间我一直在琢磨这个问题,如何对自己现有的程序进行优化?如何解决空间问题? 现在终于调试好了,时间和空间的效率都非常理想:
  1. // http://bbs.emath.ac.cn/viewthread.php?tid=1689&page=1&fromuid=8#pid21085
  2. #include <iostream>
  3. #include <ctime>
  4. #include <vector>
  5. #include <map>
  6. using namespace std;
  7. typedef unsigned int UINT32, *PUINT32;
  8. typedef unsigned __int64 UINT64, *PUINT64;
  9. typedef struct node
  10. {
  11. UINT32 key;
  12. UINT64 value;
  13. }NODE;
  14. typedef vector< NODE > NODE_VECTOR;
  15. typedef map< UINT32, UINT32 > KEY_INDEX_MAP;
  16. typedef KEY_INDEX_MAP::value_type MVT;
  17. #ifndef UInt32x32To64
  18. # define UInt32x32To64(a, b) ((UINT64)(((UINT64)(a)) * ((UINT64)(b))))
  19. #endif
  20. char szResult[128];
  21. const char * GetMin01( UINT32 n )
  22. {
  23. char * p = szResult;
  24. UINT32 i=0, j=0, d, ten, bits, index, size0, size1;
  25. UINT32 key;
  26. UINT64 value;
  27. NODE info;
  28. NODE_VECTOR vNode;
  29. KEY_INDEX_MAP mKeyIndex;
  30. KEY_INDEX_MAP::iterator it;
  31. *( p += 127 ) = '\0';
  32. // if ( 0 == n ) return p;
  33. while ( 0 == ( 1 & n ))
  34. {
  35. ++i; //times of prime 2
  36. n >>= 1;
  37. }
  38. while ( 0 == n % 5 )
  39. {
  40. ++j; //times of prime 5
  41. n /= 5;
  42. }
  43. if ( i < j ) i = j; //max times of prime 2 and prime 5
  44. memset( p -= i, '0', i * sizeof(char));
  45. if ( 1 == n )
  46. {
  47. *(--p) = '1';
  48. return p;
  49. }
  50. //special case that n+1 is 10^j
  51. i = n + 1;
  52. j = 0;
  53. while ( 0 == i % 10 )
  54. {
  55. ++j;
  56. i /= 10;
  57. }
  58. if ( 1 == i )
  59. {
  60. j *= 9;
  61. memset( p -= j, '1', j * sizeof(char));
  62. return p;
  63. }
  64. switch( n )
  65. {
  66. case 3:
  67. case 37: n = 111;
  68. break;
  69. case 7:
  70. case 13: n = 1001;
  71. break;
  72. case 337: n = 1011;
  73. break;
  74. case 367: n = 1101;
  75. break;
  76. default:
  77. break;
  78. }
  79. i = n;
  80. j = 0;
  81. while (( d = i % 10 ) <= 1 )
  82. {
  83. *(--p) = '0' + d;
  84. if ( 0 == ( i /= 10 ))
  85. {
  86. return p;
  87. }
  88. ++j;
  89. }
  90. p += j;
  91. const UINT32 INIT4BITS[] = { 0, 1, 10, 11, 100, 101, 110, 111, 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111, };
  92. for ( i=0; 16!=i; ++i )
  93. {
  94. info.key = INIT4BITS[i] % n;
  95. info.value = i;
  96. vNode.push_back( info );
  97. mKeyIndex.insert( MVT( info.key, i ));
  98. }
  99. index = i - 1;
  100. for ( bits=4, ten=10000%n, size1=size0=vNode.size(); ; )
  101. {
  102. for ( i=1; size0!=i; ++i )
  103. {
  104. d = (UINT32)( UInt32x32To64( vNode[i].key, ten ) % n );
  105. if ( mKeyIndex.end() != ( it = mKeyIndex.find( n - d )))
  106. {
  107. value = vNode[(*it).second].value;
  108. do
  109. {
  110. *(--p) = '0' + ( 1 & value );
  111. value >>= 1;
  112. } while( 0 != --bits );
  113. value = vNode[i].value;
  114. do
  115. {
  116. *(--p) = '0' + ( 1 & value );
  117. } while( 0 != ( value >>= 1 ));
  118. return p;
  119. }
  120. }
  121. for ( i=1; size1!=i; ++i )
  122. {
  123. d = (UINT32)( UInt32x32To64( vNode[i].key, ten ) % n );
  124. value = vNode[i].value << bits;
  125. for ( j=0; size0!=j; ++j )
  126. {
  127. key = vNode[j].key + d;
  128. if ( key < d || key >= n )
  129. {
  130. key -= n;
  131. }
  132. if ( mKeyIndex.end() == mKeyIndex.find( key ))
  133. {
  134. mKeyIndex.insert( MVT( info.key = key, ++index ));
  135. info.value = vNode[j].value | value;
  136. vNode.push_back( info );
  137. }
  138. }
  139. }
  140. if ( size1 == size0 )
  141. {
  142. bits <<= 1;
  143. ten = (UINT32)( UInt32x32To64( ten, ten ) % n );
  144. }
  145. else
  146. {
  147. ++bits;
  148. ten = (UINT32)( UInt32x32To64( ten, 10 ) % n );
  149. }
  150. size0 = vNode.size();
  151. if ( UInt32x32To64( size0, size0 ) <= (UINT64)n )
  152. {
  153. size1 = size0;
  154. }
  155. else
  156. {
  157. size1 = 2;
  158. }
  159. }
  160. return p;
  161. }
  162. int main( void )
  163. {
  164. UINT32 n;
  165. const char * p;
  166. while( 1 )
  167. {
  168. cout << "N=";
  169. cin >> n;
  170. if( 0 == n )
  171. {
  172. break;
  173. }
  174. clock_t start=clock();
  175. p = GetMin01( n );
  176. clock_t end=clock();
  177. cout << p << "\n";
  178. cout<< "Total cost " << end-start << "ms" << "\n" << endl;
  179. }
  180. return 0;
  181. }
复制代码
其实,因今天周六,我上午就写好了代码,但测试下来有个bug,直到刚刚才debug出问题所在,郁闷死了。 而问题出在 No.161 行,之前少加了“key < d ||”(高手肯定知道它是在判定什么的吧?), 导致在输入较大的 N 时,因未判定溢出而得不到正确结果。 现在的程序效率比 mathe 的更高(当 N 非常大时),因为它无需将数据在几个 map 间进行倒腾。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-8-15 22:26:59 | 显示全部楼层
另外,上述程序的 181、182 和 192 行可以对应修改,比如改成:
  1. // ...
  2. if ( size1 == size0 )
  3. {
  4. bits <<= 1;
  5. ten = (UINT32)( UInt32x32To64( ten, ten ) % n );
  6. }
  7. else
  8. {
  9. bits += 4;
  10. ten = (UINT32)( UInt32x32To64( ten, 10000 ) % n );
  11. }
  12. size0 = vNode.size();
  13. if ( UInt32x32To64( size0, size0 ) <= (UINT64)n )
  14. {
  15. size1 = size0;
  16. }
  17. else
  18. {
  19. size1 = 16;
  20. }
  21. }
  22. return p;
  23. }
复制代码
但实际测试下来的结果看,bits 逐步递增效果更好(我仅测了几个非常大的素数)。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-11-22 01:06 , Processed in 0.033927 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表