免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
81 [报告]
发表于 2011-05-18 10:31 |只看该作者
昨晚想了一下这个问题,有这么一个优化方法:
将1^21 * 1, 1^21 * 2, 1^21 * 3 ... 1^21 * 21, 2^21 * 1, 2^21 * 2 ... 2^21 * 21, .... 9^21 * 21一共189个数保存起来。于是原问题抓换成从这189个数中选最多9个数出来,使得他们的和满足一定的条件。整个问题的解空间小于21^9 ,这个数字大概是5000亿,采用深搜,再根据位数为21这个条件剪一下枝,最终的解空间应该不会超过100亿。

这种算法的复杂度是O(N^9),而不是O(9^N),N为位数。

论坛徽章:
0
82 [报告]
发表于 2011-05-18 10:50 |只看该作者
本帖最后由 KBTiller 于 2011-05-18 11:16 编辑

回复 81# koolcoy


    9^21不需要那么多。位数为21应该可以减去两支

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
83 [报告]
发表于 2011-05-18 19:14 |只看该作者
用python实现了一下这个算法
测试结果:
[witch@localhost ~]$ for i in 21 23 24; do
> time ./flower.py $i
> done
449177399146038697307
128468643043731391252

real    1m33.091s
user    1m31.283s
sys     0m0.123s
27879694893054074471405
27907865009977052567814
35452590104031691935943
21887696841122916288858
28361281321319229463398

real    2m49.607s
user    2m47.742s
sys     0m0.164s
174088005938065293023722
188451485447897896036875
239313664430041569350093

real    3m40.527s
user    3m38.041s
sys     0m0.160s

  1. #!/usr/bin/env python

  2. import sys

  3. LENGTH = int(sys.argv[1])
  4. TABLE = tuple([tuple([x * (i**LENGTH) for x in range(1, LENGTH + 1)])
  5.                                                 for i in range(1, 10)])
  6. MAX = 10 ** LENGTH - 1
  7. MIN = 10 ** (LENGTH - 1)

  8. def isValidNumber(number, digit):
  9.         tmp = [0] * 10
  10.         for ch in str(number):
  11.                 tmp[ord(ch) - ord('0')] += 1
  12.         tmp.pop(0)
  13.         return tmp == digit

  14. def search(left, index, partialSum, digit):
  15.         if index < 8 and left > 0:
  16.                 search(left, index + 1, partialSum, digit)

  17.         for count in range(1, left + 1):
  18.                 digit[index] = count
  19.                 value = TABLE[index][count - 1]
  20.                 sum = partialSum + value

  21.                 if sum > MAX:
  22.                         break

  23.                 if sum > MIN:
  24.                         if isValidNumber(sum, digit):
  25.                                 print sum
  26.                 if index < 8 and left > count:
  27.                         search(left - count, index + 1, sum, digit)
  28.        
  29.         digit[index] = 0

  30. def main():
  31.         digit = [0] * 9
  32.         search(LENGTH, 0, 0, digit)

  33. if __name__ == "__main__":
  34.         main()
复制代码

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
84 [报告]
发表于 2011-05-18 20:02 |只看该作者
[witch@localhost ~]$ time ./flower.py 29
23866716435523975980390369295
14607640612971980372614873089
19008174136254279995012734740
19008174136254279995012734741

real    15m38.757s
user    15m0.449s
sys     0m0.333s

论坛徽章:
0
85 [报告]
发表于 2011-05-18 20:41 |只看该作者
先mark一下,今天加班太累了。

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
86 [报告]
发表于 2011-05-18 22:42 |只看该作者
又用C++实现了一下这个算法,结果大大地出乎我的意料{:3_189:}

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

real        0m9.627s
user        0m9.582s
sys        0m0.008s
witch:~/Documents/workspace/Flower$ time ./a.out 24
174088005938065293023722
188451485447897896036875
239313664430041569350093

real        0m22.139s
user        0m22.119s
sys        0m0.006s

  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 = LENGTH - 1; i >= 0; --i) {
  83.                         std::sprintf(decimal + WIDTH * (LENGTH - 1 - i), "%09d", data[i]);
  84.                 }
  85.                 decimal[LENGTH * WIDTH] = 0;
  86.         }

  87.         void show() const {
  88.                 char decimal[LENGTH * WIDTH + 1];
  89.                 toString(decimal);
  90.                 printf("%s\n", decimal);
  91.         }

  92. private:
  93.         enum {
  94.                 BASE = 1000000000, /* This is 10^9 */
  95.                 WIDTH = 9
  96.         };
  97.         U32 data[LENGTH];

  98.         void copy(U32 that) {
  99.                 data[0] = that % BASE;
  100.                 data[1] = that / BASE;
  101.                 for (int i = 2; i < LENGTH; ++i) {
  102.                         data[i] = 0;
  103.                 }
  104.         }

  105.         static void output(const char* decimal) {
  106.                 int i = 0;
  107.                 while (decimal[i] == '0') {
  108.                         ++i;
  109.                 }
  110.                 printf("%s\n", decimal + i);
  111.         }
  112. };

  113. typedef Integer<3> Bigint;

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

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

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

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

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

  136.         createSumTable(length);
  137. }

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

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

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

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

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
87 [报告]
发表于 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
88 [报告]
发表于 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. }
复制代码

论坛徽章:
0
89 [报告]
发表于 2011-05-19 09:26 |只看该作者
只要是提供组合数的解法
各种方案的解空间是一样大的

但是
for(n9 = 1 ; n9 <= 21 ; n9++)
    for(n8 = 0 ; n8 <= 21 - n9 ; n8++)
    ……
方案对所谓的“剪枝”可能更好写

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
90 [报告]
发表于 2011-05-19 09:48 |只看该作者
回复 89# KBTiller


    显然不一样,按这种方法穷举的话,其复杂度是O(N^9),如果按各个数位上的数字来枚举的话,复杂度O(9^N),一个是多项式级的复杂度,另外一个是指数级的复杂度。复杂度跟解空间是等价的
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP