图片来自百度华容道吧。第二/三步卒子像军旗的工兵在铁道上跑——比我们的局面变化数少。
C++版注释掉判断找到解://if (a[0][1] == 3) { print_path(); break; }
程序不崩,queue_tail = 14,950,080,我的解释是:从此局面出发总共有这么多。和这个不矛盾。
“诗云”版华容道应该是可行的。
gcc 12的STL的set不快,这个程序比那个上面那个慢多了。set底层是树,unordered_set底层是Hash表。可Hash表都用自己的。- E = ' ' # 全角空格
- class Brd:
- def __str__(m): return '\n'.join([''.join(r) for r in m.b])
- def totuple(m): return tuple(tuple(r) for r in m.b)
- def put(m, blks):
- m.b = [[E] * 4 for _ in range(5)]
- for b in blks:
- if b.x < 0 or b.x + b.w > 4 or b.y < 0 or b.y + b.h > 5: return False
- for y in range(b.y, b.y + b.h):
- for x in range(b.x, b.x + b.w):
- if m.b[y][x] != E: return False
- m.b[y][x] = b.name
- return True
- class Blk:
- def __init__(m, name, x, y, w = 1, h = 1):
- m.name = name; m.x = x; m.y = y; m.w = w; m.h = h; m.old = []
- def step(m, dx, dy):
- m.old.append((m.x, m.y)); m.x += dx; m.y += dy
- def back(m): (m.x, m.y) = m.old.pop()
- brd = Brd() # 全局临时brd.
- # 每个blk有自己的old[],等于我们自己管理一些堆栈。
- blks = [
- Blk('曹', 1, 0, 2, 2),
- Blk('关', 1, 2, 2, 1),
- Blk('张', 0, 3, 1, 2),
- Blk('黄', 1, 3, 1, 2),
- Blk('赵', 2, 3, 1, 2),
- Blk('马', 3, 3, 1, 2),
- Blk('甲', 0, 0),
- Blk('乙', 0, 1),
- Blk('丙', 3, 0),
- Blk('丁', 3, 1)
- ]
- cc = blks[0]
- brd.put(blks); seen = set(); path = []
- def search (n):
- if cc.y == 3: return True
- s = str(brd) # 都可以,速度本例看不出差别
- # s = brd.totuple()
- if s in seen: return False
- seen.add(s)
- for b in blks:
- for (dx, dy) in [[-1,0],[1,0],[0,-1],[0,1]]:
- b.step(dx, dy)
- if brd.put(blks):
- path.append(str(brd))
- if search(n + 1): return True
- path.pop()
- b.back()
- return False
- import sys
- sys.setrecursionlimit(10000)
- if search(0): print(len(path), path[-1], path[0], sep='\n\n')
复制代码 [code]#include #include #include #include #include #include using namespace std;const char* NM[] = { "曹", "关", "张", "黄", "赵", "马", "丁", "丙", "乙", "甲" };const int W[] = { 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 };const int H[] = { 2, 1, 2, 2, 2, 2, 1, 1, 1, 1 };const int D[4][2] = { 0, -1, 0, 1, -1, 0, 1, 0 };struct State { uint64_t xys; // xy坐标们 int p; // 局面路径的previous // int next; // Hash表里的next bool operator< (const State& that) const { return xys < that.xys; } State& operator= (int a[10][2]); void toary(int a[10][2]); void operator= (const char* s); void print();};State& State: perator= (int a[10][2]) { xys = 0; for (int i = 0; i < 10; i++) { uint64_t x = a[0], y = a[1]; xys |= ((x (i * 5); a[0] = (xy >> 3) & 3; // x a[1] = xy & 7; // y }}void State: perator= (const char* s) { int a[10][2] = {}, p = 6; for (int x = 3; x >= 0; x--) for (int y = 4; y >= 0; y--) { #define CASE(c, i) case c: a[0] = x; a[1] = y; break; switch (s[x * 5 + y]) { CASE('c', 0) CASE('g', 1) // 曹关 CASE('z', 2) CASE('h', 3) // 张黄 CASE('l', 4) CASE('m', 5) // 子龙(l) 马 case 'p': a[p][0] = x; a[p++][1] = y; } } *this = a;}void State::print () { const char* b[5][4] = {}; int a[10][2]; toary(a); for (int i = 0; i < 10; i++) { int x = a[0], y = a[1]; for (int yy = y; yy < y + H; yy++) for (int xx = x; xx < x + W; xx++) b[yy][xx] = NM; } for (int y = 0; y < 5; y++) { for (int x = 0; x < 4; x++) printf("%s", b[y][x] ? : " "); puts(""); } puts("");}enum { QMAX = 100 * 1000 * 1000 };State states[QMAX + 40];int qh, qt = 1; // queue head, tailset seen; // 改Hash表,和states二合一bool can_move (int a[10][2], int i, int j) { // 无论成功失败, a都被修改,需要被恢复 // 别优化,a[0]和a[1]要一起改 const int x = (a[0] += D[j][0]); const int y = (a[1] += D[j][1]); if (x < 0 || x + W > 4) return false; if (y < 0 || y + H > 5) return false; uint32_t bits = 0; for (int i = 0; i < 10; i++) { const int x = a[0], y = a[1]; for (int yy = y; yy < y + H; yy++) for (int xx = x; xx < x + W; xx++) bits |= 1 |