// H: Manhattan Distance intcomputeH(state &p){ int h = 0; for (int i = 0; i < GRID; i++) { for (int j = 0; j < GRID; j++) { if (p.panel[i][j] != 0) { h += abs(rightPos[p.panel[i][j]] / GRID - i); h += abs(rightPos[p.panel[i][j]] % GRID - j); } } } return h; }
估值函数H1(欧几里得距离):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// H1: Euclidean Distance intcomputeH1(state &p){ int h = 0; for (int i = 0; i < GRID; i++) { for (int j = 0; j < GRID; j++) { if (p.panel[i][j] != 0) { int distance = (rightPos[p.panel[i][j]] / GRID - i) * (rightPos[p.panel[i][j]] / GRID - i) + (rightPos[p.panel[i][j]] % GRID - j) * (rightPos[p.panel[i][j]] % GRID - j); distance = pow(distance, 0.5); h += distance; } } } return h; }
估值函数H2(错误放置的个数):
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// H2: number of wrong position intcomputeH2(state &p){ int h = 0; for (int i = 0; i < GRID; i++) { for (int j = 0; j < GRID; j++) { if (p.panel[i][j] != 0) { if ((3 * i + j) != rightPos[p.panel[i][j]]) { h++; } } } } return h; }
使用逆序数判断状态间是否可到达:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
boolisCanSolve(state &start){ int temp[9]= {0}; int k = 0; for (int i = 0; i < GRID; i++) { for (int j = 0; j < GRID; j++) { temp[k++] = start.panel[i][j]; } } int inverseNum = 0; for (int i = 0; i < 9; i++) { for (int j = i + 1; j < 9; j++) { if (temp[i] != 0 && temp[j] != 0 && temp[i] > temp[j]) { inverseNum++; } } } return (inverseNum % 2 != 0); }
// Find the highest f value sort(openTable.begin(), openTable.end(), compareState);
state *p = openTable.back();
openTable.pop_back();
// Reach target state if (computeH2(*p) == 0) { return p; }
level = p->level + 1;
int zeroPos = findZero(*p); int zeroX = zeroPos / 3; int zeroY = zeroPos % 3; for (int i = 0; i < 4; i++) { int x_offset = 0, y_offset = 0; switch (i) { case0: // right x_offset = 0; y_offset = 1; break; case1: // left x_offset = 0; y_offset = -1; break; case2: // down x_offset = 1; y_offset = 0; break; case3: // up x_offset = -1; y_offset = 0; break; default: break; }
// out of bound if (zeroX + x_offset < 0 || zeroX + x_offset >= GRID || zeroY + y_offset < 0 || zeroY + y_offset >= GRID) { continue; } state *q = new state(level); // Initial a new state q->parent = p; *q = *p; // move zero to the new position q->panel[zeroX][zeroY] = q->panel[zeroX + x_offset][zeroY + y_offset]; q->panel[zeroX + x_offset][zeroY + y_offset] = 0;
bool isSkip = false; vector<state*>::iterator duplicate = findDuplicate(openTable, q); // If q is in OpenTable, update it if (duplicate != openTable.end()) { if (computeF(q) < computeF(*duplicate)) { (*duplicate)->level = q->level; (*duplicate)->parent = q->parent; } isSkip = true; } // If q is in CloseTable, update it duplicate = findDuplicate(closeTable, q); if (duplicate != closeTable.end()) { if (computeF(q) < computeF(*duplicate)) { delete *duplicate; closeTable.erase(duplicate); //cout << "Test: " << q->panel[1][1] << endl; openTable.push_back(q); isSkip = true; } }
if (!isSkip) { openTable.push_back(q); } }
closeTable.push_back(p); } }
九数码
在八数码的基础上做了修改:
估值函数把0也计算,这里以H2为例:
1 2 3 4 5 6 7 8 9 10 11 12
// H2: number of wrong position intcomputeH2(state &p){ int h = 0; for (int i = 0; i < GRID; i++) { for (int j = 0; j < GRID; j++) { if ((3 * i + j) != rightPos[p.panel[i][j]]) { h++; } } } return h; }
// Expand sub nodes for (int e = 0; e < 9; e++) { int x = e / 3; int y = e % 3;
for (int i = 0; i < 4; i++) { int x_offset = 0, y_offset = 0; switch (i) { case0: // right x_offset = 0; y_offset = 1; break; case1: // left x_offset = 0; y_offset = -1; break; case2: // down x_offset = 1; y_offset = 0; break; case3: // up x_offset = -1; y_offset = 0; break; default: break; }
// out of bound if (x + x_offset < 0 || x + x_offset >= GRID || y + y_offset < 0 || y + y_offset >= GRID) { continue; } state *q = new state(level); // Initial a new state q->parent = p; *q = *p; // switch two position int temp = q->panel[x][y]; q->panel[x][y] = q->panel[x + x_offset][y + y_offset]; q->panel[x + x_offset][y + y_offset] = temp;
bool isSkip = false; vector<state*>::iterator duplicate = findDuplicate(openTable, q); // If q is in OpenTable, update it if (duplicate != openTable.end()) { if (computeF(q) < computeF(*duplicate)) { (*duplicate)->level = q->level; (*duplicate)->parent = q->parent; } isSkip = true; }