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

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

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

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

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

×
精华
在十进制中,给定正整数N(0<N<10^8),求最小的正整数M,使得M可被N整除,且M每个数字为0或1之一。

要求:
1、编程环境(包括使用第三方类库)不限;
2、对于任意指定的N或连续的N,尽可能快地输出对应的M。

额外奖励:最先公布出在 0<N<108 范围内对应 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-4-26 23:17 , Processed in 0.067400 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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