华容道——持续改进中

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned uint;

const char* NM[][4] = { "","","","", {"西",""}, {"",""}, {"",""}, {"",""}, {"",""}, {""}, {""}, {""}, {""} };
int W[] = { 2, 2, 2, 2, 2, 2, 1, 1, 1, 1 }; // 默认5个水平条,随后修改
int H[] = { 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
const int D[][2] = { 0, -1, 0, 1, -1, 0, 1, 0 };

enum { QMAX = 38 * 1000 * 1000 };
struct State {
  unsigned xs, ys;
  int p; // 路径的previous
  void operator=(const char* s);
  void print(const char* s = "");
} states[QMAX + 10 * 4];
int qh, qt = 1; // queue head, tail
int a[10][2], b[5][4]; // 坐标与棋盘;int比byte稍快
unsigned seen[1 << (30 - 5)]; // 30位y;32=1<<5

// 宏的名字和(间不能有空格
#define froma(s) for (int i = 0; i < 10; i++) { (s).xs = ((s).xs << 2) | a[i][0]; (s).ys = ((s).ys << 3) | a[i][1]; }

// 修改全局变量b;调函数开销还是挺大; \后不能有注释
#define toary(s) { \
  memset(b, 1, sizeof(b)); \
  uint X = (s).xs, Y = (s).ys; \
  for (int i = 9; i >= 0; i--) { \
    const int& x = a[i][0] = X & 3; X >>= 2; \
    const int& y = a[i][1] = Y & 7; Y >>= 3; \
    for (int yy = y; yy < y + H[i]; yy++) \
      for (int xx = x; xx < x + W[i]; xx++) \
        b[yy][xx] = 0; \
  } \
}

void State::operator= (const char* s) {
  int p = 6;
  for (int x = 3; x >= 0; x--)
    for (int y = 4; y >= 0; y--) {
    #define CASE(c, i) case c: a[i][0] = x; a[i][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; // pawn
    }
  }
  static const char*  S[] = { "gg", "zz", "hh", "ll", "mm" };
  for (int i = 0; i < 5; i++)
    if (strstr(s, S[i])) W[i+1] = 1, H[i+1] = 2;
  froma(*this);
}

void State::print (const char* s) {
  toary(*this);
  const char* b[5][4] = {};
  int idx[10] = {};
  for (int i = 0; i < 10; i++) {
    int x = a[i][0], y = a[i][1];
    for (int yy = y; yy < y + H[i]; yy++)
      for (int xx = x; xx < x + W[i]; xx++)
        b[yy][xx] = NM[i][idx[i]++];
  }
  for (int y = 0; y < 5; y++) {
    for (int x = 0; x < 4; x++) printf("%s", b[y][x] ? : " ");
    puts("");
  }
  printf("%s\n", s);
}

void print_path () { // 用数组存放的单链表就地翻转
  int prev = -1, next = -1, n = 0;
  for (int cur = qh; cur != -1;) {
    next = states[cur].p;
    states[cur].p = prev;
    prev = cur; cur = next;
    ++n;
  }
  for (int p = 0; p != -1; p = states[p].p) states[p].print();
  printf("%d\n", n);
}

#define peek(i) const uint key = states[i].xs ^ states[i].ys, ki = key >> 5, km = 1 << (key & 0x1f)
#define aboo seen[ki] |= km

int main (int argc, char* argv[]) {
  //states[0] = "pp zz""ccghh""ccgll""pp mm";
  states[0] = (argc == 2) ? argv[1] : "pzzpg""cc  g""ccllm""phhpm";
  states[0].p = -1;
  peek(0); aboo;

  for (; qh < qt; qh++) {
    toary(states[qh]);

    if (a[0][1] == 3) { print_path(); break; } // 曹操的y

    for (int i = 9; i >= 0; i--)
    for (int j = 0; j < 4; j++) {
      int ok;
      const int ox = a[i][0], oy = a[i][1];
      int x = (a[i][0] += D[j][0]), y = (a[i][1] += D[j][1]);
      if (x < 0 || x + W[i] > 4 || y < 0 || y + H[i] > 5) ok = 0;
      else {
        if (i >= 6) { // 卒单独处理;没啥用
          if (j == 1) y = oy + H[i];
          else if (j == 3) x = ox + W[i];
          ok = b[y][x];
        }
        else {
          if (j == 0) ok = b[y][x] & (!(W[i] - 1) | b[y][x + 1]); // W[i]1或2; 不更快
          else if (j == 1) { y = oy + H[i]; ok = b[y][x] && (W[i] == 1 || b[y][x + 1]); }
          else if (j == 2) ok = b[y][x] & (!(H[i] - 1) | b[y + 1][x]);
          else { x = ox + W[i]; ok = b[y][x] && (H[i] == 1 || b[y + 1][x]); }
        }
      }

      if (ok) {
        froma(states[qt]);
        peek(qt);
        if (seen[ki] & km) states[qt].xs = states[qt].ys = 0;
        else { aboo; states[qt++].p = qh; }
      }

      a[i][0] -= D[j][0]; a[i][1] -= D[j][1];
    }
  }

  printf("%d\n", qt); return 0;
}

x在0~3之间,2位,y在0~4之间,3位。10个棋子,所有的x用20位,y用30位,拼起来50位。

用64位int的话,可以找到最优解。此版本找到的是不很优的:有些局面被误判为已见过,绕远了。

 

这里〕:

  • 67行Python DFS
  • C++ BFS 最优解。64位别忘了常数加ull后缀,变量uint64_t(x)。

 

0.01458秒版(-m avx2...):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
typedef unsigned uint;

const char* NM[][4] = { "","","","", {"西",""}, {"",""}, {"",""}, {"",""}, {"",""}, {""}, {""}, {""}, {""} };
int W[] = { 2, 2, 2, 2, 2, 2, 1, 1, 1, 1 }; // 默认5个水平条,随后修改
int H[] = { 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
#if 1
const int D[][2] = { 0, -1, 0, 1, -1, 0, 1, 0 };
#else
const int D[][2] = { 0, 1, 0, -1, -1, 0, 1, 0 };
#endif

enum { QMAX = 3800 * 10000 };
struct State {
  uint xs, ys;
  uint p; // 局面路径的previous
  void operator=(const char* s);
  void operator=(const State& that) { memcpy(this, &that, sizeof(*this)); }
  void print(const char* s = "");
} q[QMAX + 10 * 4];
int qh, qt = 1; // queue head, tail
int a[10][2], b[5][4]; // 坐标与棋盘;int 比byte稍快
unsigned seen[1 << (30 - 5)]; // 30位y;32=1<<5

// 宏的名字和(间不能有空格
#define froma(s) for (int i = 0; i < 10; i++) { (s).xs = ((s).xs << 2) | a[i][1]; (s).ys = ((s).ys << 3) | a[i][0]; }

// 修改全局变量b;调函数开销还是挺大; \后不能有注释
#define toary(s) { \
  memset(b, 1, sizeof(b)); \
  uint X = (s).xs, Y = (s).ys; \
  for (int i = 9; i >= 0; i--) { \
    const int& x = a[i][1] = X & 3; X >>= 2; \
    const int& y = a[i][0] = Y & 7; Y >>= 3; \
    for (int yy = y; yy < y + H[i]; yy++) \
      for (int xx = x; xx < x + W[i]; xx++) \
        b[yy][xx] = 0; \
  } \
}

void State::operator= (const char* s) {
  int p = 6;
  for (int x = 3; x >= 0; x--)
    for (int y = 4; y >= 0; y--) {
    #define CASE(c, i) case c: a[i][1] = x; a[i][0] = 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][1] = x; a[p++][0] = y; // pawn
    }
  }
  static const char*  S[] = { "gg", "zz", "hh", "ll", "mm" };
  for (int i = 0; i < 5; i++)
    if (strstr(s, S[i])) W[i+1] = 1, H[i+1] = 2;
  froma(*this);
}

void State::print (const char* s) {
  toary(*this);
  const char* b[5][4] = {};
  int idx[10] = {};
  for (int i = 0; i < 10; i++) {
    int x = a[i][1], y = a[i][0];
    for (int yy = y; yy < y + H[i]; yy++)
      for (int xx = x; xx < x + W[i]; xx++)
        b[yy][xx] = NM[i][idx[i]++];
  }
  for (int y = 0; y < 5; y++) {
    for (int x = 0; x < 4; x++) printf("%s", b[y][x] ? : " ");
    puts("");
  }
  printf("%s\n", s);
}

int print_path (double tm) { // 用数组存放的单链表就地翻转
  int prev = -1, next = -1, n = 0;
  for (int cur = qh; cur != -1;) {
    next = q[cur].p;
    q[cur].p = prev;
    prev = cur; cur = next;
    ++n;
  }
  for (int p = 0; p != -1; p = q[p].p) q[p].print();
  return printf("%d %.6f ", n, tm);
}

#define peek(i) const uint key = q[i].xs ^ q[i].ys, ki = key >> 5, km = 1 << (key & 0x1f)
#define aboo seen[ki] |= km

int main (int argc, char* argv[]) {
  //q[0] = "pp zz""ccghh""ccgll""pp mm";
  q[0] = (argc == 2) ? argv[1] : "pzzpg""cc  g""ccllm""phhpm";
  q[0].p = -1;
  peek(0); aboo;

  for (double tm = clock(); qh < qt; qh++) {
    toary(q[qh]);

    if (a[0][0] == 3) return print_path((clock() - tm) / CLOCKS_PER_SEC);

    // 不do ... while (0)了
    #define add_state() { \
      froma(q[qt]); \
      peek(qt); \
      if (seen[ki] & km) q[qt].xs = q[qt].ys = 0; \
      else { aboo; q[qt++].p = qh; } \
    }

    for (int j = 0; j < 4; j++) {
      int ok;
      for (int i = 0; i < 6; i++) {
        const int ox = a[i][1], oy = a[i][0];
        int x = (a[i][1] += D[j][0]), y = (a[i][0] += D[j][1]);
        if (x < 0 || x + W[i] > 4 || y < 0 || y + H[i] > 5) ok = 0;
        else {
          if (j == 0) ok = b[y][x] & (!(W[i] - 1) | b[y][x + 1]); // W[i]1或2; 不更快
          else if (j == 1) { y = oy + H[i]; ok = b[y][x] && (W[i] == 1 || b[y][x + 1]); }
          else if (j == 2) ok = b[y][x] & (!(H[i] - 1) | b[y + 1][x]);
          else { x = ox + W[i]; ok = b[y][x] && (H[i] == 1 || b[y + 1][x]); }
        }
        if (ok) add_state();
        a[i][1] -= D[j][0]; a[i][0] -= D[j][1];
      }
      for (int i = 6; i < 10; i++) {
        const int ox = a[i][1], oy = a[i][0];
        int x = (a[i][1] += D[j][0]), y = (a[i][0] += D[j][1]);
        if (x < 0 || x + W[i] > 4 || y < 0 || y + H[i] > 5) ok = 0;
        else {
          if (j == 1) y = oy + H[i];
          else if (j == 3) x = ox + W[i];
          ok = b[y][x];
        }
        if (ok) add_state();
        a[i][1] -= D[j][0]; a[i][0] -= D[j][1];
      }
    }
  }

  return printf("%d\n", qt);
}
View Code

 

吕震宇的C#程序〕,Hash size不会大:512MB内存的电脑。CircularLinkedList.cs里的BeginProcess递归;不是最优解。算阶乘能递归也能循环,也许他的是BFS.

 
穷举一横四竖〕,Intel N100单线程11秒,易改12线程。五个长条中选k个横放,C(5,0)+...+C(5,5)=2**5。

 

〔 Modern perfect hashing〕〔 推箱子搜索

 
得意了不到两天,发现自己很土。
找得少比找得快更重要。对调块和方向的循环,直接干到0.155秒。
memset后再几乎全部覆盖?!空格也做成棋子。
醉心于压缩空间,其实3600万*24=864M; sizeof(有位域的struct)往往不小。
W*2+H当类型T。算hash时用T [5][4], 解决对称性。
检测移动时用另一个byte [5][4],元素是棋子的编号。移动空格。

 

操作空格太麻烦了。下面的版本只用了类型,0.21秒,最优解。可切换std::set和cwisstable

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <immintrin.h>
#include <xmmintrin.h>
#include <set>
#include "cwisstable.h"

const char* NM[][4] = { "","","","", {"西",""}, {"",""}, {"",""}, {"",""}, {"",""}, {""}, {""}, {""}, {""} };
int W[] = { 2, 2, 2, 2, 2, 2, 1, 1, 1, 1 }; // 默认5个水平条,随后修改
int H[] = { 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
int T[10]; // Type
const int D[][2] = { 0, -1, 0, 1, -1, 0, 1, 0 }; // 后面用下标判断移动方向:别改!

enum { MAX = 3600 * 10000 };
struct State {
  uint8_t a[10][2];
#define CCY a[0][0] // 曹操的y
  int p; // 局面路径的previous
#define cpy20(dst, src) _mm_storeu_si128((__m128i*)dst, _mm_loadu_si128((__m128i*)src)); *(int*)((uint8_t*)dst+16) = *(int*)((const uint8_t*)src+16)
  void operator= (const State& s) { cpy20(a, s.a); p = s.p; }
  void operator=(const char* s);
  void print(const char* s = "");
} q[MAX + 10 * 4]; // 最多40个move. 不过MAX很大,而且没判断qt < MAX
int qh, qt = 1; // queue head, tail

void State::operator= (const char* s) {
  int p = 6;
  for (int x = 3; x >= 0; x--)
    for (int y = 4; y >= 0; y--) {
    #define CASE(c, i) case c: a[i][1] = x; a[i][0] = y; break;
    switch (s[x * 5 + y]) {
    // 曹关张黄子龙(l)马
    CASE('c', 0) CASE('g', 1) CASE('z', 2) CASE('h', 3) CASE('l', 4) CASE('m', 5)
    case 'p': a[p][1] = x; a[p++][0] = y; // pawn
    }
  }
  static const char*  S[] = { "gg", "zz", "hh", "ll", "mm" };
  for (int i = 0; i < 5; i++) if (strstr(s, S[i])) W[i+1] = 1, H[i+1] = 2;
  for (int i = 0; i < 10; i++) T[i] = W[i] * 2 + H[i];
}

#define set2DArrayByCoordInA(b, what) \
for (int i = 0; i < 10; i++) { \
  const int x = a[i][1], y = a[i][0]; \
  for (int yy = y; yy < y + H[i]; yy++) \
    for (int xx = x; xx < x + W[i]; xx++) b[yy][xx] = what; \
}

void State::print (const char* s) {
  int idx[10] = {};
  const char* b[5][4] = {};
  set2DArrayByCoordInA(b, NM[i][idx[i]++])
  for (int y = 0; y < 5; y++) {
    for (int x = 0; x < 4; x++) printf("%s", b[y][x] ? : " ");
    puts("");
  }
  printf("%s\n", s);
}

void print_path () { // 数组存的单链表就地翻转
  int prev = -1, next = -1, n = 0;
  for (int cur = qh; cur != -1;) {
    next = q[cur].p;
    q[cur].p = prev;
    prev = cur; cur = next;
    ++n;
  }
  for (int p = 0; p != -1; p = q[p].p) q[p].print();
  printf("%d\n", n);
}

struct TA { // Type Array
  uint8_t b[5][4];
  const bool operator< (const TA& t) const { return memcmp(b, t.b, 20) < 0; }
};
#define Ah TA ta __attribute__((aligned(32))), ta2; \
  _mm256_store_si256((__m256i*)ta.b, _mm256_setzero_si256()); \
  set2DArrayByCoordInA(ta.b, T[i])

#ifdef stl
std::set<TA> set;
#define add_state { cpy20(q[qt].a, a); \
  Ah if (set.find(ta) == set.end()) { set.insert(ta); q[qt++].p = qh; } \
}
#else
CWISS_DECLARE_FLAT_HASHSET(Set, TA); Set set = Set_new(MAX);
#define add_state { cpy20(q[qt].a, a); \
  Ah if (!Set_contains(&set, &ta)) { Set_insert(&set, &ta); q[qt++].p = qh; } \
}
#endif

int main (int argc, char* argv[]) {
  //q[0] = "pp zz""ccghh""ccgll""pp mm";
  q[0] = (argc == 2) ? argv[1] : "pzzpg""cc  g""ccllm""phhpm";
  q[0].p = -1;
  uint8_t a[10][2];
#ifdef stl
  Ah set.insert(ta);
#else
  Ah Set_insert(&set, &ta);
#endif

  double tm = clock();
  for (; qh < qt; qh++) {
    if (q[qh].CCY == 3) { print_path(); break; }

    cpy20(a, q[qh].a);
    uint8_t b[5][4] __attribute__((aligned(32))), overflow[12];
    _mm256_store_si256((__m256i*)b, _mm256_set1_epi8(1));
    set2DArrayByCoordInA(b, 0)

    int qt1 = qt;
    for (int j = 0; j < 4; j++) {
      int ok;
      for (int i = 0; i < 6; i++) {
        const int ox = a[i][1], oy = a[i][0];
        int x = (a[i][1] += D[j][0]), y = (a[i][0] += D[j][1]);
        if (x < 0 || x + W[i] > 4 || y < 0 || y + H[i] > 5) ok = 0;
        else { // D[]的顺序不能换!
          if (j == 0) ok = b[y][x] & (!(W[i] - 1) | b[y][x + 1]); // W[i]1或2; 不更快
          else if (j == 1) { y = oy + H[i]; ok = b[y][x] && (W[i] == 1 || b[y][x + 1]); }
          else if (j == 2) ok = b[y][x] & (!(H[i] - 1) | b[y + 1][x]);
          else { x = ox + W[i]; ok = b[y][x] && (H[i] == 1 || b[y + 1][x]); }
        }
        if (ok) add_state
        a[i][1] -= D[j][0]; a[i][0] -= D[j][1];
      }
      for (int i = 6; i < 10; i++) {
        const int ox = a[i][1], oy = a[i][0];
        int x = (a[i][1] += D[j][0]), y = (a[i][0] += D[j][1]);
        if (x < 0 || x + W[i] > 4 || y < 0 || y + H[i] > 5) ok = 0;
        else {
          if (j == 1) y = oy + H[i];
          else if (j == 3) x = ox + W[i];
          ok = b[y][x];
        }
        if (ok) add_state
        a[i][1] -= D[j][0]; a[i][0] -= D[j][1];
      }
    }
#if 1
    int qt2 = qt - 1;
    if (qt2 > qt1 && q[qt2].CCY < q[qt1].CCY) { State t = q[qt1]; q[qt1] = q[qt2]; q[qt2] = t; }
#endif
  }

  printf("%.6f %d\n", (clock() - tm) / CLOCKS_PER_SEC, qt);
  return 0;
}
View Code

 

上述代码有bug,为了避免再犯,把State:a改成了aa. 〔0.02秒 最优解版

 

HTML看路径:

Screenshot_20251023_151840

← ↑ → ↓前后。做“推鞋子”游戏?〔这里〕有很多。

 1 <html lang="zh-CN">
 2 <head><meta charset="UTF-8">
 3 <style>
 4 table { 
 5   position: absolute;
 6   top: 50%; left: 50%; transform: translate(-50%, -50%);
 7   border-collapse: collapse; 
 8 }
 9 td {
10   width: 66px; height: 66px;
11   text-align: center;
12   font-size: 40px;
13 }
14 input, button { 
15   position: absolute;
16   left: 50%; transform: translateX(-50%);
17   bottom: 40px;
18   font-size: 16pt;
19 }
20 input { display: none; }
21 button { padding: 8px; }
22 pre { display:none; }
23 img { padding: 0; margin: 0 }
24 </style></head><body>
25 <table id="tbl"></table>
26 <input type="file" id="file" accept=".txt">
27 <button id="btn" onclick="file.click()" tabindex="-1">打开文件</button>
28 <script>
29 let d = document, lines, idx, pic
30 
31 for (let r = 0; r < 5; r++) {
32   let row = d.createElement('tr')
33   for (let c = 0; c < 4; c++) row.appendChild(d.createElement('td'))
34   tbl.appendChild(row)
35 }
36 
37 function draw () {
38   for (let i = 0; i < 5; i++)
39     for (let j = 0; j < 4; j++) {
40       let cell = tbl.rows[i].cells[j], s = lines[idx + i][j]
41       cell.textContent = s
42       let c = 'white'
43       if ('曹贼真爽'.includes(s)) c = 'gold'
44       else if ('西施'.includes(s)) c = 'forestgreen'
45       else if ('昭君'.includes(s)) c = 'orangered'
46       else if ('貂蝉'.includes(s)) c = 'blueviolet'
47       else if ('甄姬'.includes(s)) c = 'lightseagreen'
48       else if ('玉环'.includes(s)) c = 'hotpink'
49       else if (s === '') cell.innerHTML = '<img src="' + pic + '">'
50       cell.style.background = c
51     }
52 }
53 
54 file.addEventListener('change', (e)=>{
55   let reader = new FileReader()
56   reader.onload = function(e) { lines = e.target.result.split('\n'); idx = 0; draw() }
57   if (e.target.files.length) reader.readAsText(e.target.files[0])
58 })
59 
60 d.addEventListener('keydown', (e)=>{
61   btn.blur()
62   let k = e.key
63   if (k === 'ArrowDown' || k === 'ArrowRight') {
64     if (idx + 12 < lines.length) idx += 6
65     draw()
66   }
67   else if (k === 'ArrowLeft' || k === 'ArrowUp') {
68     if (idx >= 6) idx -= 6;
69     draw()
70   }
71 })
72 
73 onload = ()=>{ pic = d.getElementsByTagName('pre')[0].innerHTML }
74 </script>
75 </body>
76 <pre>data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAtGVYSWZJSSoACAAAAAYAEgEDAAEAAAABAAAAGgEFAAEAAABWAAAAGwEFAAEAAABeAAAAKAEDAAEAAAACAAAAEwIDAAEAAAABAAAAaYcEAAEAAABmAAAAAAAAAEgAAAABAAAASAAAAAEAAAAGAACQBwAEAAAAMDIxMAGRBwAEAAAAAQIDAACgBwAEAAAAMDEwMAGgAwABAAAA//8AAAKgBAABAAAAQAAAAAOgBAABAAAAQAAAAAAAAABuEYT5AAADgUlEQVR4nO2a20tUURSHv5kmzFuZlhJBGRVhRUJX6X6DlKLIghKC6KGnoKDX/oBeCnzorR6jKBCpKJCiggoCEw26QjetLCMrsouVObFhTRyG0dnLGWfOOXM+WJwzw16cvX/7vvaGgICAgABXEALyM/3RMO4hAtTksgADQEUuCxAFynJZgBBQkssCFI1wEJzgFwGKRyhAnV8EmCTjgLbVTPWLAJXAT6XPJqDTLwJMB34pfXYCT/wiwCzgsyL9eGAL8MwvAiwE3itr36Tv94MAYaAa6FH47AGepuPDbmCOTIPdlunNyL8GeOwXAVbJFPjWMv1uyfsDPwnQo5gFdsnzIT6hE2ixTFsODAJ/gUI/tIBKYBrQYZl+o2ycXgDf/SDAennetUy/QZ4p93+3CNAgwZDrlukX+6n/T5HC31L49MqMYYTzfAtoAMYA5yzTFwCl8m4GQs/TBvxRxAIrpPaNHcTjzJWCXFD4lDsEsJ02XcsxKUi9wmeyQwDTBWbjUSLAOxnQ8hR+ixwCGGvEo2yVApxQ+h2OE+A3UIUHaZYCLFH63Y4TwNg1PEa51Jx2ITNf+n00gW3HQ+yXTB9R+p0ZovDGWvEQlyXT8xQ+S4ep/ZiZDZXrKZLQ9yul38UkhTe22QtL4TpgnBTIlirLwhV6QYBt8ryk8Dlgmc8uXE5YFj5fFYufscAHi+bfIUESV7NAMtuk8FlnUfgBR4zA1V1gpWMxozktSsYp4J4XBFghT82cbbPM1S6ns0aX7P01o/WdJM0/pYPRTFItGW5X+JSJYIn6fOz9bKoZC5O53V9sE2RLvWyb4znueH+DR2gFPipugYUlXBZf+y1yjyD2+xAeoBj4BKxV+DQO0edr4yLDmmhSxskDlgOr5fTHNuh5epj53ogZO0SJyiYpJSKkH7Mi2ysxP2eT75fjrJeyGeqWmgxJrK9GWokJfSfiEdAn78+BZW4cA6qAGxart5HYScd3jsp/+W6ZBQokU/eVfV3DTcd7r3QJ7a2yUaFWmnZ0FG0w7vBkH/CFLFOSJEyVTmtPcKT2Oh2FiIzQr1QONM3pTiY4H/fbXI74RhbZkaGaN3Y1QfzAXJK4QpZje01DrNXTZX0SOR6Nqfo/oRT9zW3NmcAMh1U63jXTVJ8Mpm0ylTan4wpMMkKj/QFgogRC82XgDMnBSKxwPyRMZp4BAQEBAWSQf0M3aYd8JHYVAAAAAElFTkSuQmCC</pre>
77 </html>
View Code
posted @ 2025-10-22 15:14  华容道专家  阅读(11)  评论(0)    收藏  举报