找回密码
 欢迎注册
楼主: gxqcn

[悬赏] 最少分组方案算法

[复制链接]
发表于 2008-8-26 20:23:41 | 显示全部楼层
不是吧 只要正向得到 形式如2pq + 1 类型素数就可以了吧
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
回复

使用道具 举报

发表于 2008-9-13 16:45:50 | 显示全部楼层
对 2048 以内的素数分组 有 92 组的结果: No. 1 : 2039 2029 1033 No. 2 : 2027 2017 1049 No. 3 : 2011 2003 1063 No. 4 : 1999 1997 1069 No. 5 : 1993 1987 1061 No. 6 : 1979 1973 1097 No. 7 : 1951 1949 1129 No. 8 : 1933 1931 1123 No. 9 : 1913 1907 1171 No. 10 : 1901 1889 1193 No. 11 : 1879 1877 1217 No. 12 : 1873 1871 1223 No. 13 : 1867 1861 1231 No. 14 : 1847 1831 1259 No. 15 : 1823 1811 1297 No. 16 : 1801 1789 1327 No. 17 : 1787 1783 1321 No. 18 : 1777 1759 1373 No. 19 : 1753 1747 1399 No. 20 : 1741 1733 1423 No. 21 : 1723 1721 1447 No. 22 : 1709 1699 1471 No. 23 : 1697 1693 1493 No. 24 : 1669 1667 1543 No. 25 : 1663 1657 1553 No. 26 : 1637 1627 1609 No. 27 : 1621 1619 1613 No. 28 : 1607 1601 1597 No. 29 : 1583 1579 1571 No. 30 : 1567 1559 1549 No. 31 : 1531 1523 1511 No. 32 : 1499 1489 1487 No. 33 : 1483 1481 1459 No. 34 : 1453 1451 1439 No. 35 : 1433 1429 1427 No. 36 : 1409 1381 1367 No. 37 : 1361 1319 1307 No. 38 : 1303 1301 1291 No. 39 : 1289 1283 1279 2 No. 40 : 1277 1249 1237 No. 41 : 1229 1213 1201 No. 42 : 1187 1181 1163 No. 43 : 1153 1151 1117 No. 44 : 1109 1103 1093 3 No. 45 : 1091 1087 1051 No. 46 : 1039 1031 1021 No. 47 : 1019 1013 1009 No. 48 : 997 991 983 No. 49 : 977 971 967 No. 50 : 953 947 941 5 No. 51 : 937 929 919 No. 52 : 911 907 887 No. 53 : 883 881 877 No. 54 : 863 859 857 No. 55 : 853 839 829 7 No. 56 : 827 823 821 No. 57 : 811 809 797 No. 58 : 787 773 769 No. 59 : 761 757 751 No. 60 : 743 739 733 No. 61 : 727 719 709 11 No. 62 : 701 691 683 No. 63 : 677 673 661 13 No. 64 : 659 653 647 No. 65 : 643 641 631 No. 66 : 619 617 613 17 No. 67 : 607 601 599 19 No. 68 : 593 587 577 No. 69 : 571 569 563 23 No. 70 : 557 547 541 No. 71 : 523 521 509 29 No. 72 : 503 499 491 31 No. 73 : 487 479 467 37 No. 74 : 463 461 457 43 No. 75 : 449 443 439 47 No. 76 : 433 431 421 53 No. 77 : 419 409 401 61 No. 78 : 397 389 383 71 No. 79 : 379 373 367 79 No. 80 : 359 353 349 97 No. 81 : 347 337 331 109 No. 82 : 317 313 311 139 No. 83 : 307 293 283 167 No. 84 : 281 277 271 199 No. 85 : 269 263 257 233 No. 86 : 251 241 239 229 No. 87 : 227 223 211 197 No. 88 : 193 191 181 179 No. 89 : 173 163 157 151 No. 90 : 149 137 131 127 No. 91 : 113 107 103 83 41 No. 92 : 101 89 73 67 59
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
回复

使用道具 举报

 楼主| 发表于 2008-9-13 16:57:58 | 显示全部楼层
楼上说说,你是如何做到的? 这个悬赏至今刚好满一个月了, 之前一直没有更好的突破, 所以,打算继续悬赏一个月, 对于有突破的算法或结论, 除了可以得到悬赏的100枚金币, 还可获得本人私下转让的金币(数目不菲的)。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
回复

使用道具 举报

发表于 2008-9-13 18:16:38 | 显示全部楼层
  1. #include < iostream.h >
  2. #include < math.h >
  3. #include "D:/HugeCalc/HugeCalc.h" // 公共接口
  4. #include "D:/HugeCalc/HugeInt.h" // 10进制系统
  5. #include "D:/HugeCalc/HugeIntX.h" // 16进制系统
  6. #pragma message( "automatic link to D:/HugeCalc/HugeCalc.lib" )
  7. #pragma comment( lib, "D:/HugeCalc/HugeCalc.lib" )
  8. const unsigned __int16 Pri1024 = 172; // 1024 以内的素数个数
  9. const unsigned __int16 Pri2048 = 309; // 2048 以内的素数个数
  10. const __int64 BOUND32 = (1ul << 32) - 1;
  11. const __int64 BOUND14 = (1ul << 14) - 1;
  12. const __int64 BOUND10 = (1ul << 10) - 1;
  13. typedef CHugeIntX integer;
  14. unsigned __int16 arr[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039 };
  15. //const unsigned __int32 ProblemSize = 1023;
  16. //unsigned __int16 arr[ProblemSize];
  17. __int32 MinimumGroup(const unsigned __int16* const arr, const unsigned __int16 _SIZE, const __int64 _BOUND);
  18. int main(/*int argc, char* argv[]*/ void)
  19. {
  20. __int32 result;
  21. //for ( __int16 i=0; i<ProblemSize; i++) arr[ i ] = i + 2;
  22. cout << "Call " << HugeCalc::GetVer() << endl;
  23. HugeCalc::EnableTimer();
  24. HugeCalc::ResetTimer(0, TIMER_UNIT_ms);
  25. //result = MinimumGroup(arr, ProblemSize, BOUND32);
  26. //result = MinimumGroup(arr, 25, BOUND14); // 贪婪法=10,最优=9
  27. //result = MinimumGroup(arr, 36, 22500ul); // 贪婪法=15,最优=14
  28. //result = MinimumGroup(arr, 72, 8100ul); // 贪婪法=最优=49
  29. //result = MinimumGroup(arr, Pri1024, BOUND10); // 贪婪法=最优=162
  30. //result = MinimumGroup(arr, Pri1024, BOUND10*29); // 贪婪法=最优=133
  31. result = MinimumGroup(arr, Pri1024, BOUND32);
  32. //result = MinimumGroup(arr, Pri2048, BOUND32);
  33. HugeCalc::EnableTimer( FALSE );
  34. cout << endl << "Best result = " << result << endl;
  35. cout << endl << HugeCalc::GetTimerStr() << endl;
  36. system( "pause" );
  37. return 0;
  38. }
  39. // 函数名: MinimumGroup
  40. // 函数功能: 求出把一组正整数 arr[0] ~ arr[_SIZE-1] 划分成最少的组数的方法,使得每组里所有数之积均不大于 _BOUND
  41. //
  42. // 输入参数:
  43. // arr: unsigned __int16,数组指针,要求 arr[] 是升序排列
  44. // _SIZE: unsigned __int16,数组的大小
  45. // _BOUND: __int64,分组的乘积最大值
  46. //
  47. // 输出参数: __int32,最小分组数
  48. // 结果为 0: _SIZE = 0
  49. // 结果为 -1: _BOUND < arr[_SIZE-1]
  50. // 结果为 -2: arr 不是升序排列
  51. //
  52. // 版本 : 1.2.5.9
  53. // 修改时间: 2008-9-11 00:30
  54. //
  55. // 存在问题: 运算效率很低,限界条件不够精细
  56. // 下一版本改进措施; 乘法变加法,把 arr[]、_BOUND 都取对数,然后扩大某个倍数,化成整数加减运算
  57. __int32 MinimumGroup(const unsigned __int16* const arr, const unsigned __int16 _SIZE, const __int64 _BOUND)
  58. {
  59. __int32 i, j, k, icur, g, gMin, gMax, gCur, top, bottom, top0, bottom1, top1, Lpro, numOfBig, Lpromin;
  60. __int32 *bUsed, *pbuf;
  61. __int64 product, maxV, minGV, *pmaxV, *pminGV, *ppro;
  62. top0 = _SIZE - 1;
  63. if ( 0 == _SIZE ) return (0);
  64. if ( _BOUND < arr[top0] ) return (-1);
  65. for ( i=0; i<top0; ++i )
  66. {
  67. if ( arr[i] > arr[i+1] )
  68. return (-2);
  69. }
  70. if ( 0 == arr[0] || 1 == arr[top0] ) return (1);
  71. for ( i=0 ; 1 == arr[i] ; ++i ); // 1不参加运算
  72. if ( i == top0 ) return (1);
  73. bottom1 = i;
  74. for (maxV=_BOUND/arr[bottom1], i=top0 ; i>bottom1 && arr[i]>maxV ; --i ); // 只能单独做一组的数
  75. if ( i - bottom1 < 2 ) return (_SIZE - i);
  76. top1 = i;
  77. integer hollpro(arr[bottom1]), grpV(_BOUND), b(_BOUND);
  78. for ( j=1, i=1+bottom1 ; i<=top1 ; ++i )
  79. {
  80. hollpro *= arr[i];
  81. if ( hollpro > grpV )
  82. {
  83. grpV *= b;
  84. ++j;
  85. }
  86. }
  87. grpV = 0;
  88. numOfBig = top0 - top1;
  89. gMin = j + numOfBig;
  90. if ( j == 1 ) return (gMin);
  91. // 用贪婪法求分组数的一个上界 gMax,此方法来自 gxqcn
  92. bUsed = new __int32 [_SIZE];
  93. for ( i=0; i<_SIZE; ++i ) bUsed[i] = 0;
  94. cout << endl;
  95. for ( gMax=0, bottom=0, top=top0 ; bottom != top ; )
  96. {
  97. ++gMax;
  98. cout << "No. " << gMax << " : ";
  99. //for ( product=1, maxV=_BOUND, i=top ; i >= bottom; --i )
  100. for ( maxV=_BOUND, i=top ; i >= bottom; --i )
  101. {
  102. if ( !bUsed[i] && arr[i] <= maxV )
  103. {
  104. cout << " " << arr[i];
  105. //maxV = _BOUND / ( product *= arr[i] );
  106. maxV /= arr[i];
  107. bUsed[i] = 1;
  108. }
  109. }
  110. //cout << " " << product;
  111. cout << endl;
  112. while ( bottom != top && bUsed[top] ) --top;
  113. while ( bottom != top && bUsed[bottom] ) ++bottom;
  114. }
  115. if ( !bUsed[top] )
  116. {
  117. ++gMax;
  118. //cout << "No. " << gMax << " : " << arr[top] << " " << arr[top] << endl;
  119. cout << "No. " << gMax << " : " << arr[top] << endl;
  120. }
  121. if ( gMax == gMin )
  122. {
  123. delete [] bUsed;
  124. return (gMax); // 上界 = 下界
  125. }
  126. // 尝试组数更小的方案
  127. // 求第一组的数字的个数
  128. for ( Lpromin=0, maxV=_BOUND, i=top1 ; i >= bottom1; --i )
  129. {
  130. if ( arr[i] <= maxV )
  131. {
  132. maxV /= arr[i];
  133. ++Lpromin;
  134. }
  135. }
  136. k = gMax - numOfBig;
  137. for ( maxV=_BOUND, i=bottom1; arr[i]<=maxV; ++i ) maxV /= arr[i] ;
  138. Lpro = i - bottom1 + 1; // 最长乘式的因子数+1
  139. j = Lpro * gMax;
  140. pbuf = new __int32 [j]; // 所有分组因子下标表格
  141. pmaxV = new __int64 [j]; // 同组的下一个乘积因子允许的最大值
  142. ppro = new __int64 [j]; // 本组前几个因子的乘积
  143. pminGV = new __int64 [gMax]; // 每一组乘积允许的最小值
  144. integer *pGV, *pB, q, r, c;
  145. pGV = new integer [gMax]; // 本组之后未分配的数的乘积
  146. pB = new integer [k]; // 界限参数(_BOUND的乘幂)
  147. for ( i=0; i<j; ++i ) pbuf[i] = 0;
  148. for ( i=0; i<j; ++i ) pmaxV[i] = 0;
  149. for ( i=0; i<j; ++i ) ppro[i] = 0;
  150. for ( top=top0, i=1; i<=numOfBig ; ++i, --top )
  151. {
  152. pbuf[i * Lpro ] = 1;
  153. pbuf[i * Lpro + 1] = top;
  154. ppro[i * Lpro ] = 1;
  155. ppro[i * Lpro + 1] = arr[top];
  156. bUsed[top] = 1;
  157. }
  158. icur = Lpro-2+bottom1;
  159. if ( Lpromin <= 2 )
  160. {
  161. for ( i=icur; i<top1; ++i ) pmaxV[i] = _BOUND - ( _BOUND % arr[i] );
  162. }
  163. else
  164. {
  165. for ( i=icur; i<top1; ++i )
  166. {
  167. maxV = _BOUND / arr[i];
  168. g = __int32(maxV % arr[bottom1]);
  169. for ( j=bottom1+1; g>0 && j<i; ++j)
  170. {
  171. gCur = __int32(maxV % arr[j]);
  172. if ( g > gCur )
  173. g = gCur;
  174. }
  175. pmaxV[i] = ( maxV - g ) * arr[i];
  176. }
  177. }
  178. // 选择排序
  179. for ( i=icur; i<icur+k-1; ++i )
  180. {
  181. for ( g=i, maxV=pmaxV[i], j=i+1; j<top1; ++j )
  182. {
  183. if ( maxV < pmaxV[j] )
  184. {
  185. maxV = pmaxV[j];
  186. g = j;
  187. }
  188. }
  189. if ( g != i )
  190. {
  191. pmaxV[g] = pmaxV[i];
  192. pmaxV[i]= maxV;
  193. }
  194. }
  195. for ( pB[0]=1, pB[1]=pmaxV[icur], j=icur, i=2; i<k; ++i )
  196. {
  197. ++j;
  198. pB[i] = pB[i-1] * ( q = pmaxV[j] );
  199. }
  200. //for ( pB[0]=1, pB[1]=b, i=2; i<k; ++i ) pB[i] = pB[i-1] * b;
  201. b = 0;
  202. for ( i=numOfBig+1; i<gMax; ++i ) pmaxV[i * Lpro] = _BOUND;
  203. pGV[numOfBig] = hollpro;
  204. for ( gCur=gMax-1 ; gCur >= gMin ; --gCur ) // 组数循环
  205. {
  206. for ( top=top1, i=bottom=bottom1; i<=top; ++i ) bUsed[i] = 0;
  207. for ( g=numOfBig+1 ; g<gCur ; ) // g 循环
  208. {
  209. q.Div( pGV[g-1], pB[gCur-g], &r );
  210. if ( !(!r) ) ++q;
  211. pminGV[g] = minGV = q;
  212. k = 1;
  213. pbuf[g*Lpro+k] = top;
  214. ppro[g*Lpro+k] = product = arr[top];
  215. pmaxV[g*Lpro+k] = maxV = _BOUND / product;
  216. bUsed[top] = 1;
  217. icur = --top;
  218. // 生成第 g 组乘积
  219. do {
  220. for ( i=icur; i>=bottom; --i )
  221. {
  222. if ( !bUsed[i] && arr[i] <= maxV )
  223. {
  224. ++k;
  225. pbuf[g*Lpro+k] = i;
  226. ppro[g*Lpro+k] = product *= arr[i];
  227. pmaxV[g*Lpro+k] = maxV /= arr[i] ;
  228. bUsed[i] = 1;
  229. }
  230. }
  231. if ( product >= minGV ) // 进入下一组
  232. {
  233. pbuf[g*Lpro] = k;
  234. pGV[g] = pGV[g-1] / (c = product);
  235. while ( bottom != top && bUsed[top] ) --top;
  236. while ( bottom != top && bUsed[bottom] ) ++bottom;
  237. ++g;
  238. break;
  239. }
  240. // 生成下一个乘积
  241. do {
  242. j = bottom;
  243. do {
  244. i = pbuf[g*Lpro+k];
  245. bUsed[i] = 0;
  246. --k;
  247. if ( i > top )
  248. {
  249. top = i;
  250. }
  251. else if ( i < bottom )
  252. {
  253. bottom = i;
  254. }
  255. } while ( k >= 1 && i < j );
  256. if ( k >= 1 )
  257. {
  258. icur = --i;
  259. maxV = pmaxV[g*Lpro+k];
  260. product = ppro[g*Lpro+k];
  261. break;
  262. }
  263. --g; // 退回到上一组
  264. if ( numOfBig == g ) // 退到底了
  265. {
  266. delete [] pB;
  267. delete [] pGV;
  268. delete [] pminGV;
  269. delete [] ppro;
  270. delete [] pmaxV;
  271. delete [] pbuf;
  272. delete [] bUsed;
  273. return (gCur+1);
  274. }
  275. k = pbuf[g*Lpro];
  276. minGV = pminGV[g];
  277. } while ( 1 ); // end of 生成下一个乘积
  278. } while ( 1 ); // end of 生成第 g 组乘积
  279. } // end of g 循环
  280. for ( j=0, i=top; i>=bottom; --i) // 最后一组
  281. {
  282. if ( !bUsed[i] )
  283. {
  284. ++j;
  285. pbuf[g*Lpro+j] = i;
  286. }
  287. }
  288. pbuf[g*Lpro] = j;
  289. // 输出
  290. cout << endl << "groups = " << gCur << endl;
  291. for ( i=1 ; i <= gCur ; ++i )
  292. {
  293. cout << "No. " << i << " : ";
  294. for ( k=pbuf[i*Lpro], j=1 ; j <= k ; ++j )
  295. cout << " " << arr[ pbuf[i * Lpro + j] ];
  296. cout << endl;
  297. }
  298. cout << endl;
  299. } // end of 组数循环
  300. delete [] pB;
  301. delete [] pGV;
  302. delete [] pminGV;
  303. delete [] ppro;
  304. delete [] pmaxV;
  305. delete [] pbuf;
  306. delete [] bUsed;
  307. return (gMin);
  308. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
回复

使用道具 举报

 楼主| 发表于 2008-9-13 19:01:43 | 显示全部楼层
这么说来,我给出的程序效率是很高的,结果也是相当不错的。 谢谢你的代码,有空时我琢磨一下。 前面第26#说了,该问题更注重输出结果,因为是拿它作应用的; 即便运行时间长点也不碍事,反正只要运行一次。 当然,若有更优化的通用算法,则是上上品了。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
回复

使用道具 举报

发表于 2008-9-13 20:58:24 | 显示全部楼层
为什么不用对数? 仅仅是因为是浮点运算? 假设某组数字的对数和为s s <= 32 32 - s <= 1/16 是否算和优化的一组?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
回复

使用道具 举报

发表于 2020-2-1 18:49:14 | 显示全部楼层
这跟一维下料是等价问题。只求满足根数最少的组合方式之一?(可能有多种)
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

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

GMT+8, 2024-11-21 20:12 , Processed in 0.023700 second(s), 14 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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