注册 |登录

0GiNr技术社区论坛程序算法 › 查看主题

889

查看

8

回复
返回列表

Rank: 7Rank: 7Rank: 7

金钱
2961 元 
经验
380 点 
威望
26 点 
贡献
3 点 
精华
go

用 A* 解决八数码问题.

1
发表于 2010-2-1 09:23 | 只看该作者 | 倒序看帖 | 打印
凡本论坛原创内容,其作者享有著作权,未经许可谢绝转载。
本帖最后由 ForeverBell 于 2010-2-1 09:37 编辑

这个版块看起来似乎挺冷清的. 发点东西热闹下.
最近在系统地学习搜索等技巧, 少不了要接触一下 A* 启发式搜索, 自然地, 也少不了八数码经典的问题..
POJ 正好也有一道 Eight. 那就拿这道题开刀吧..
估价函数为未回家的数码的数量和.       
似乎还是慢了点, 250ms, 但又不是太慢...就是写起来麻烦点..呃, 废话到此为止.
btw: 似乎 cpp 标签又不好使了..
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>

  4. using namespace std;

  5. #define HEAP_PARENT(i)                        (i >> 1)
  6. #define HEAP_LEFT(i)                        (i << 1)
  7. #define HEAP_RIGHT(i)                        ((i << 1) + 1)
  8. #define HEAP_KEY(i)                                (heap[i].key)

  9. const int heap_max = 400000;
  10. struct heap_data {
  11.         int step; // depth
  12.         int key; // f
  13.         int v; // node
  14.         unsigned int path[4]; // path
  15. } heap[heap_max] = {0};

  16. class class_heap {
  17. private:
  18.         int heap_size;

  19.         void swap(heap_data &arg1, heap_data &arg2)
  20.         {
  21.                 heap_data temp_heap;       
  22.                 temp_heap = arg1; arg1 = arg2; arg2 = temp_heap;
  23.         }

  24.         int heap_min_up(int node)
  25.         {
  26.                 int parent;

  27.                 parent = HEAP_PARENT(node);
  28.                 if (node > 1 && HEAP_KEY(parent) > HEAP_KEY(node)) {
  29.                         swap(heap[parent], heap[node]);
  30.                         return heap_min_up(parent);
  31.                 }
  32.                 return node;
  33.         }

  34.         int heap_min_down(int node)
  35.         {
  36.                 int left, right;
  37.                 int smallest = node;

  38.                 left = HEAP_LEFT(node);
  39.                 right = HEAP_RIGHT(node);
  40.                 if (left <= heap_size && HEAP_KEY(left) < HEAP_KEY(node)) {
  41.                         smallest = left;
  42.                 }
  43.                 if (right <= heap_size && HEAP_KEY(right) < HEAP_KEY(smallest)) {
  44.                         smallest = right;
  45.                 }
  46.                 if (smallest != node) {
  47.                         smallest = 0;
  48.                         if (left <= heap_size) {
  49.                                 smallest = left;
  50.                         }
  51.                         if (right <= heap_size && HEAP_KEY(right) < HEAP_KEY(left)) {
  52.                                 smallest = right;
  53.                         }
  54.                         if (smallest) {
  55.                                 swap(heap[smallest], heap[node]);
  56.                                 return heap_min_down(smallest);
  57.                         }
  58.                 }
  59.                 return node;
  60.         }

  61. public:
  62.         class_heap() { heap_size = 0; }

  63.         void insert(heap_data key)
  64.         {
  65.                 heap[++heap_size] = key;
  66.                 heap_min_up(heap_size);
  67.         }

  68.         heap_data extract_min()
  69.         {
  70.                 heap_data result = heap[1];

  71.                 swap(heap[1], heap[heap_size--]);
  72.                 heap_min_down(1);
  73.                 return result;
  74.         }

  75.         bool empty()
  76.         {
  77.                 return (heap_size == 0);
  78.         }
  79. };

  80. class_heap heap_table;
  81. bool hash[400000] = {0};
  82. const int dstst = 123456780;
  83. const int table[10] = {0, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
  84. const int markl[10][5] = {  
  85.         {0, 0, 0, 0, 0},
  86.         {0, 2, 0, 0, 4},
  87.         {0, 3, 1, 0, 5},
  88.         {0, 0, 2, 0, 6},
  89.         {0, 5, 0, 1, 7},
  90.         {0, 6, 4, 2, 8},
  91.         {0, 0, 5, 3, 9},
  92.         {0, 8, 0, 4, 0},
  93.         {0, 9, 7, 5, 0},
  94.         {0, 0, 8, 6, 0}
  95. };
  96. const char markc[5] = {0, 'r', 'l', 'u', 'd'};
  97. const int fac[10] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};

  98. int calc_hash(int key)
  99. {
  100.         int result = 0;
  101.         int decode[10] = {0};

  102.         for (int i = 9; i > 0; --i) {
  103.                 decode[i] = key % 10;
  104.                 key /= 10;
  105.         }
  106.         for (int i = 1; i <= 9; ++i) {
  107.                 for (int j = i + 1; j <= 9; ++j) {
  108.                         if (decode[j] < decode[i]) {
  109.                                 result += fac[9 - i];
  110.                         }
  111.                 }               
  112.         }
  113.         return result;
  114. }

  115. int calc_h(int key)
  116. {
  117.         int key1, key2, result;

  118.         key1 = dstst; key2 = key; result = 0;
  119.         for (int i = 1; i <= 9; ++i) {
  120.                 if ((key1 % 10 != key2 % 10) && (key2 % 10 != 0)) {
  121.                         ++result;
  122.                 }
  123.                 key1 /= 10;
  124.                 key2 /= 10;
  125.         }
  126.         return result;
  127. }

  128. void expand_node(heap_data old_state)
  129. {
  130.         int i, n, k, t, h;
  131.         int decode[10] = {0};
  132.         heap_data new_state;

  133.         t = old_state.v;
  134.         for (i = 9; i > 0; --i) {
  135.                 decode[i] = t % 10;
  136.                 t /= 10;
  137.                 if (decode[i] == 0) {
  138.                         k = i;
  139.                 }
  140.         }
  141.         for (i = 1; i <= 4; ++i) {
  142.                 n = markl[k][i];
  143.                 if (n != 0) {
  144.                         t = old_state.v;
  145.                         t -= table[n] * decode[n];
  146.                         t += table[k] * decode[n];                       
  147.                         h = calc_hash(t);
  148.                         if (!hash[h]) {
  149.                                 new_state.v = t;
  150.                                 new_state.key = old_state.step + calc_h(t);                               
  151.                                 new_state.step = old_state.step + 1;
  152.                                 memcpy(new_state.path, old_state.path, 16);
  153.                                 new_state.path[old_state.step / 16] |= ((i - 1) << old_state.step % 16 * 2);
  154.                                 hash[h] = true;
  155.                                 heap_table.insert(new_state);
  156.                         }
  157.                 }
  158.         }
  159. }

  160. void astar_search()
  161. {
  162.         heap_data node;
  163.         int flag = false;

  164.         while (!heap_table.empty()) {
  165.                 node = heap_table.extract_min();
  166.                 if (node.v == dstst) {
  167.                         for (int i = 0; i < node.step; ++i) {
  168.                                 cout<<markc[node.path[i / 16] % 4 + 1];
  169.                                 node.path[i / 16] >>= 2;
  170.                         }
  171.                         flag = true;
  172.                         break;
  173.                 } else {
  174.                         expand_node(node);
  175.                 }
  176.         }
  177.         if (!flag) {
  178.                 cout<<"unsolvable"<<endl;
  179.         }
  180. }

  181. int main()
  182. {
  183.         int src = 0;
  184.         char ch;
  185.         heap_data srcst;

  186.         for (int i = 1; i <= 9; ++i) {
  187.                 cin>>ch;
  188.                 if (ch != 'x') {
  189.                         ch -= '0';
  190.                         src += table[i] * ch;
  191.                 }
  192.         }
  193.         hash[calc_hash(src)] = true;
  194.         srcst.v = src;
  195.         srcst.key = calc_h(src);
  196.         srcst.step = 0;
  197.         memset(srcst.path, 0, 16);
  198.         heap_table.insert(srcst);
  199.         astar_search();
  200.         return 0;
  201. }
复制代码
写的太乱, 不好意思.
    • FlowerCode: 精彩代码金钱 + 180 元 威望 + 1 点

TOP

0GiNr核心团队

“花”指令

Rank: 12Rank: 12

金钱
1508 元 
经验
3248 点 
威望
365 点 
贡献
34 点 
精华
2
发表于 2010-2-1 14:43 | 只看该作者
FB神牛恐怕都忘了咱有这个版块了吧
最近在学基本的优化算法,希望半年到一年内能搞定一些简单的OI题目。
FlowerCode 保留随时编辑此帖的权利,恕不另行通知。本帖可能包括一些技术上的不准确性或打字错误。FlowerCode “按原样”提供本帖,不包括任何明示或暗含的保证,包括但不限于适销性或适用于某种特殊用途的保证。

TOP

Rank: 7Rank: 7Rank: 7

金钱
2961 元 
经验
380 点 
威望
26 点 
贡献
3 点 
精华
3
发表于 2010-2-1 16:46 | 只看该作者
FB神牛恐怕都忘了咱有这个版块了吧
最近在学基本的优化算法,希望半年到一年内能搞定一些简单的OI题目。 ...
FlowerCode 发表于 2010-2-1 14:43


FC 要搞 ACM 了!

TOP

0GiNr核心团队

“花”指令

Rank: 12Rank: 12

金钱
1508 元 
经验
3248 点 
威望
365 点 
贡献
34 点 
精华
4
发表于 2010-2-1 22:45 | 只看该作者
回复 3# ForeverBell


    ACM 就算能做我也不做,太伤脑细胞了。

TOP

Rank: 7Rank: 7Rank: 7

金钱
2961 元 
经验
380 点 
威望
26 点 
贡献
3 点 
精华
5
发表于 2010-2-2 09:22 | 只看该作者
本帖最后由 ForeverBell 于 2010-2-2 09:24 编辑

今天又换了个启发函数, 为所有数码离家的曼哈顿距离之和.
似乎这个更快一点(16ms). 看样子 A* 里启发决定一切.
  1. const int dis[10][10] = {
  2.         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  3.         {0, 0, 1, 3, 1, 2, 3, 2, 3, 4},
  4.         {0, 1, 0, 1, 2, 1, 2, 3, 2, 3},
  5.         {0, 2, 1, 0, 3, 2, 1, 4, 3, 2},
  6.         {0, 1, 2, 3, 0, 1, 2, 1, 2, 3},
  7.         {0, 2, 1, 2, 1, 0, 1, 2, 1, 2},
  8.         {0, 3, 2, 1, 2, 1, 0, 3, 2, 1},
  9.         {0, 2, 3, 4, 1, 2, 3, 0, 1, 2},
  10.         {0, 3, 2, 3, 2, 1, 2, 1, 0, 1},
  11.         {0, 4, 3, 2, 3, 2, 1, 2, 1, 0},
  12. };
  13. int calc_h(int key)
  14. {
  15.         int result = 0;

  16.         for (int i = 9; i > 0; --i) {
  17.                 result += dis[i][key % 10];
  18.                 key /= 10;
  19.         }
  20.         return result;
  21. }
复制代码

TOP

大牛

灌水之王

Rank: 4Rank: 4

金钱
32344 元 
经验
537 点 
威望
47 点 
贡献
1 点 
精华
6
发表于 2010-2-2 19:37 | 只看该作者
"看样子 A* 里启发决定一切"没有启发函数那就不是A*了……
好的启发可以让你没有冗余搜索,相当智能……
坏的启发还不如直接写双向广搜,速度也是超快。
FC想看算法的话,很推荐《算法艺术与信息学竞赛》+《算法艺术与信息学竞赛学习指导》,学习指导高清PDF在Olympiad in Informatics Beginners' Home下载(for free),话说里面对智能搜索写了不少。
BTW,总觉得IB写过类似的代码……
用广度优先学习更多的算法!用深度优先学习更难的算法!
My blog:hi.baidu.com/klarkzby

TOP

Rank: 7Rank: 7Rank: 7

金钱
2961 元 
经验
380 点 
威望
26 点 
贡献
3 点 
精华
7
发表于 2010-2-2 20:28 | 只看该作者
本帖最后由 ForeverBell 于 2010-2-2 20:33 编辑
"看样子 A* 里启发决定一切"没有启发函数那就不是A*了……
好的启发可以让你没有冗余搜索,相当智能……
坏 ...
wangweinoo1 发表于 2010-2-2 19:37


iceboy 啥时候写过了?
ps: 没启发函数 A* 就退化成 BFS 了~

TOP

大牛

灌水之王

Rank: 4Rank: 4

金钱
32344 元 
经验
537 点 
威望
47 点 
贡献
1 点 
精华
8
发表于 2010-2-2 20:56 | 只看该作者
呃,貌似我记错了……

TOP

Rank: 1

金钱
575 元 
经验
234 点 
威望
1 点 
贡献
0 点 
精华
9
发表于 2010-2-8 11:50 | 只看该作者
我在想搞这个会不会老得比较快
看到我就头大

TOP

0GiNr安全门户 |联系我们

GMT+8, 2010-9-7 20:39.

Powered by Discuz! X1

© 2001-2010 Comsenz Inc.