免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: DNFCF
打印 上一主题 下一主题

[算法] 变态的算法题 [复制链接]

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
11 [报告]
发表于 2011-05-18 22:49 |显示全部楼层
改一行代码:typedef Integer<4> Bigint
{:3_189:}
witch:~/Documents/workspace/Flower$ time ./a.out 31
1927890457142960697580636236639
2309092682616190307509695338915
1145037275765491025924292050346

real        2m55.434s
user        2m52.737s
sys        0m0.200s

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
12 [报告]
发表于 2011-05-18 23:55 |显示全部楼层
本帖最后由 koolcoy 于 2011-05-18 23:59 编辑

把sprintf调用去掉后竟然{:3_182:}{:3_182:}{:3_190:}{:3_190:}

witch:~/Documents/workspace/Flower$ time ./a.out 21
449177399146038697307
128468643043731391252

real        0m2.424s
user        0m2.030s
sys        0m0.003s
witch:~/Documents/workspace/Flower$ time ./a.out 31
1927890457142960697580636236639
2309092682616190307509695338915
1145037275765491025924292050346

real        0m26.691s
user        0m26.639s
sys        0m0.020s

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <cstdlib>

  4. template<int LENGTH>
  5. class Integer {
  6.         typedef unsigned int U32;
  7.         typedef unsigned long long U64;
  8. public:
  9.         Integer() {
  10.                 for (int i = 0; i < LENGTH; ++i) {
  11.                         data[i] = 0;
  12.                 }
  13.         }

  14.         Integer(U32 that) {
  15.                 copy(that);
  16.         }

  17.         const Integer& operator = (U32 that) {
  18.                 copy(that);
  19.                 return *this;
  20.         }

  21.         const Integer& operator += (const Integer& that) {
  22.                 int carry = 0;
  23.                 for (int i = 0; i < LENGTH; ++i) {
  24.                         data[i] += that.data[i] + carry;
  25.                         if (data[i] > BASE) {
  26.                                 carry = data[i] / BASE;
  27.                                 data[i] = data[i] % BASE;
  28.                         } else {
  29.                                 carry = 0;
  30.                         }
  31.                 }
  32.                 return *this;
  33.         }

  34.         const Integer& operator *= (U32 that) {
  35.                 U64 carry = 0;
  36.                 for (int i = 0; i < LENGTH; ++i) {
  37.                         U64 tmp = (U64)data[i] * (U64)that + carry;
  38.                         if (tmp > BASE) {
  39.                                 carry = tmp / BASE;
  40.                                 data[i] = tmp % BASE;
  41.                         } else {
  42.                                 carry = 0;
  43.                                 data[i] = tmp;
  44.                         }
  45.                 }
  46.                 return *this;
  47.         }

  48.         Integer operator + (const Integer& that) const {
  49.                 Integer tmp = *this;
  50.                 return tmp += that;
  51.         }

  52.         Integer operator * (U32 that) const {
  53.                 Integer tmp = *this;
  54.                 return tmp *= that;
  55.         }

  56.         bool operator > (const Integer& that) const {
  57.                 for (int i = LENGTH - 1; i >= 0; --i) {
  58.                         if (data[i] > that.data[i]) {
  59.                                 return true;
  60.                         } else if (data[i] < that.data[i]) {
  61.                                 return false;
  62.                         }
  63.                 }
  64.                 return false;
  65.         }

  66.         bool operator < (const Integer& that) const {
  67.                 return std::memcmp(data, that.data, sizeof(data)) != 0
  68.                                 && !(*this > that);
  69.         }

  70.         void validate(char digit[9]) const {
  71.                 char decimal[LENGTH * WIDTH + 1];
  72.                 toString(decimal);

  73.                 char actual[10] = {0};
  74.                 for (int i = 0; i < WIDTH * LENGTH; ++i) {
  75.                         ++actual[decimal[i] - '0'];
  76.                 }
  77.                 if (std::memcmp(actual + 1, digit, 9) == 0) {
  78.                         output(decimal);
  79.                 }
  80.         }

  81.         void toString(char* decimal) const {
  82.                 for (int i = 0; i < LENGTH; ++i) {
  83.                         convertChunk(data[LENGTH - i - 1], decimal + WIDTH * i);
  84.                 }
  85.                 decimal[LENGTH * WIDTH] = 0;
  86.         }

  87. private:
  88.         enum {
  89.                 BASE = 1000000000, /* This is 10^9 */
  90.                 WIDTH = 9
  91.         };
  92.         U32 data[LENGTH];

  93.         static void output(const char* decimal) {
  94.                 int i = 0;
  95.                 while (decimal[i] == '0') {
  96.                         ++i;
  97.                 }
  98.                 printf("%s\n", decimal + i);
  99.         }

  100.         static void convertChunk(U32 digit, char* decimal) {
  101.                 for (int i = 0; i < WIDTH; ++i) {
  102.                         decimal[WIDTH - 1 - i] = digit % 10 + '0';
  103.                         digit /= 10;
  104.                 }
  105.         }

  106.         void copy(U32 that) {
  107.                 data[0] = that % BASE;
  108.                 data[1] = that / BASE;
  109.                 for (int i = 2; i < LENGTH; ++i) {
  110.                         data[i] = 0;
  111.                 }
  112.         }
  113. };

  114. typedef Integer<SIZE> Bigint;

  115. Bigint MIN;
  116. Bigint MAX;
  117. Bigint** TABLE;

  118. void createSumTable(int length) {
  119.         TABLE = new Bigint*[9];
  120.         for (int i = 0; i < 9; ++i) {
  121.                 TABLE[i] = new Bigint[length];

  122.                 TABLE[i][0] = i + 1;
  123.                 for (int j = 1; j < length; ++j) {
  124.                         TABLE[i][0] *= (i + 1);
  125.                 }

  126.                 for (int j = 1; j < length; ++j) {
  127.                         TABLE[i][j] = TABLE[i][0] * (j + 1);
  128.                 }
  129.         }
  130. }

  131. void initialize(int length) {
  132.         MIN = 10;
  133.         for (int i = 0; i < length - 2; ++i) {
  134.                 MIN *= 10;
  135.         }
  136.         MAX = MIN * 10;

  137.         createSumTable(length);
  138. }

  139. void search(int left, int index, Bigint partialSum, char* digit) {
  140.         if (index < 8 && left > 0) {
  141.                 search(left, index + 1, partialSum, digit);
  142.         }
  143.         for (int count = 1; count < left + 1; ++count) {
  144.                 digit[index] = count;
  145.                 Bigint sum = partialSum + TABLE[index][count - 1];

  146.                 if (sum > MAX) {
  147.                         break;
  148.                 }
  149.                 if (sum > MIN) {
  150.                         sum.validate(digit);
  151.                 }
  152.                 if (index < 8 && left > count) {
  153.                         search(left - count, index + 1, sum, digit);
  154.                 }
  155.         }
  156.         digit[index] = 0;
  157. }

  158. int main(int argc, char** argv) {
  159.         int length = 0;
  160.         if (argc != 2 || sscanf(argv[1], "%d", &length) != 1 || length <= 0) {
  161.                 std::fprintf(stderr, "Usage: %s <length>\n", argv[0]);
  162.         }

  163.         initialize(length);
  164.         char* digit = (char*)std::calloc(length, 1);
  165.         search(length, 0, Bigint(0), digit);
  166.         return 0;
  167. }
复制代码

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
13 [报告]
发表于 2011-05-19 09:48 |显示全部楼层
回复 89# KBTiller


    显然不一样,按这种方法穷举的话,其复杂度是O(N^9),如果按各个数位上的数字来枚举的话,复杂度O(9^N),一个是多项式级的复杂度,另外一个是指数级的复杂度。复杂度跟解空间是等价的

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
14 [报告]
发表于 2011-05-19 10:09 |显示全部楼层
两种算法的组合数是不一样的,这两种算法有着本质的区别。
如果按照“各个数位上的数字来枚举”的话,即10楼的算法,数字 123XXXX和321XXXX是两种不同的情况,需要计算两次。
如果按照“1出现的次数为n1,2出现的次数n2,3出现的次数为n3...”这种方法来枚举的话123XXXX和321XXXX是同一种情况,只需要计算一次。

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
15 [报告]
发表于 2011-05-19 10:40 |显示全部楼层
回复 94# KBTiller

但是有个问题,按照10楼得算法,当你验证后发现123XXXX不满足条件,怎么知道321XXXX是否满足条件呢?如果不知道的话,那么你就还要验证321XXXX是否满足条件。也就是说对于123XXXX和321XXXX这两个数字你需要验证两次。但是按照我的那种算法,如果发现123XXXX不满足条件后,我就可以肯定321XXXX不满足条件。

ps: 对于21位的数字,俺已经突破1.4秒了{:3_203:}

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
16 [报告]
发表于 2011-05-19 11:09 |显示全部楼层
回复 97# KBTiller

Pentium(R) Dual-Core  CPU  E5700  @ 3.00GHz 32位cygwin
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP