按照《算法竞赛入门经典》书的思路写的代码, 但很却很遗憾,最终还是WA了, 可以用IDA*写这题, 思路清晰且代码清晰易懂。
dfs算法:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
using namespace std;
struct cNode {
int next;
int v;
};
struct Node {
int chess[24];
int steps;
string succession;
bool operator <(const Node& t1) const {
return steps > t1.steps;
}
};
const int classify[8][7] = {
{ 0, 2, 6,11,15,20,22},
{ 1, 3, 8,12,17,21,23},
{10, 9, 8, 7, 6, 5, 4},
{19,18,17,16,15,14,13},
{23,21,17,12,8,3,1},
{22,20,15,11,6,2,0},
{13,14,15,16,17,18,19},
{4,5,6,7,8,9,10},
};
const int mid[8] = { 6,7,8,11,12,15,16,17 };
char letter[8] = { 'A','F','B','E','H','C','G','D' };
int chess[24];
int bestSteps;
int maxn = 1000000;
int head[1000000];
vector<cNode> vec;
void init() {
memset(head, -1, sizeof(head));
vec.clear();
}
bool try_(Node& t1) {
int v = 0;
//压缩了状态,24位压缩成了8位, 就取中间的8位,很显然运行速快了,但是结果就不正确了,具体修改我也不知道。
//状态是否能压缩,取决于某些状态于某些状态的扩展结点是相同的;换句话说: 当某些状态于某些状态的扩展结点相同,他们可以被压缩成一种状态表示;
for (int i = 0; i < 8; i++) {
v = v << 1;
if (t1.chess[mid[i]]) v += 1;
}
cNode temp;
int h = v % maxn;
int u = head[h];
while (u != -1) {
if (vec[u].v == v)
return false;
u = vec[u].next;
}
temp.next = head[h];
temp.v = v;
vec.push_back(temp);
head[h] = vec.size() - 1;
return true;
}
bool isResult(Node& t, int curi) {
for (int i = 0; i < 8; i++) {
if (t.chess[mid[i]] != curi)
return false;
}
return true;
}
void bfs(int& steps, string& succession2, int curi) {
priority_queue<Node> q;
Node newnode;
newnode.steps = 0;
newnode.succession = "";
memcpy(newnode.chess, chess, sizeof(int) * 24);
q.push(newnode);
init();
try_(newnode);
while (!q.empty()) {
Node top = q.top();
q.pop();
if (top.steps >= bestSteps)
return;
if (isResult(top, curi)) {
steps = top.steps;
succession2 = top.succession;
return ;
}
for (int i = 0; i < 8; i++) {
memcpy(newnode.chess, top.chess, sizeof(int) * 24);
newnode.steps = top.steps + 1;
newnode.succession = top.succession;
newnode.succession.push_back('A' + i);
int tmp = newnode.chess[classify[i][0]];
for (int j = 0; j < 6; j++) newnode.chess[classify[i][j]] = newnode.chess[classify[i][j + 1]];
newnode.chess[classify[i][6]] = tmp;
if (try_(newnode)) {
q.push(newnode);
}
}
}
}
int main() {
int firstChess[24],num;
string succession2,succession;
while (cin >> firstChess[0] && firstChess[0] != 0) {
for (int i = 1; i < 24; i++)
cin >> firstChess[i];
bestSteps = maxn;
for (int i = 1; i <= 3; i++) {
int steps = 0;
for (int j = 0; j < 24; j++)
if (firstChess[j] != i) {
chess[j] = 0;
}
else
chess[j] = i;
bfs(steps, succession2, i);
if (bestSteps > steps && steps != 0) {
bestSteps = steps;
succession = succession2;
num = i;
}
}
cout << succession << "\n" << num << endl;
}
}
IDA*算法
// UVa1343 The Rotation Game
// Rujia Liu
// This solutions uses IDA* instead of BFS described in the book, because it's shorter 8-)
// It's shorter because no need for lookup tables and "automatically" lexicographically smallest solution.
#include<cstdio>
#include<algorithm>
using namespace std;
/*
00 01
02 03
04 05 06 07 08 09 10
11 12
13 14 15 16 17 18 19
20 21
22 23
*/
// lines E~H are computed with the help of rev[]
int line[8][7]={
{ 0, 2, 6,11,15,20,22}, // A
{ 1, 3, 8,12,17,21,23}, // B
{10, 9, 8, 7, 6, 5, 4}, // C
{19,18,17,16,15,14,13}, // D
};
const int rev[8] = {5, 4, 7, 6, 1, 0, 3, 2}; // reverse lines of each line
// center squares
const int center[8] = {6, 7, 8, 11, 12, 15, 16, 17};
int a[24];
char ans[1000];
bool is_final() {
for(int i = 0; i < 8; i++)
if (a[center[i]] != a[center[0]]) return false;
return true;
}
int diff(int target) {
int ans = 0;
for(int i = 0; i < 8; i++)
if(a[center[i]] != target) ans++;
return ans;
}
inline int h() {
return min(min(diff(1), diff(2)), diff(3));
}
inline void move(int i) {
int tmp = a[line[i][0]];
for(int j = 0; j < 6; j++) a[line[i][j]] = a[line[i][j+1]];
a[line[i][6]] = tmp;
}
bool dfs(int d, int maxd) {
if(is_final()) {
ans[d] = '\0';
printf("%s\n", ans);
return true;
}
if(d + h() > maxd) return false;
for(int i = 0; i < 8; i++) {
ans[d] = 'A' + i;
move(i);
if(dfs(d+1, maxd)) return true;
move(rev[i]);
}
return false;
}
int main() {
for(int i = 4; i < 8; i++)
for(int j = 0; j < 7; j++) line[i][j] = line[rev[i]][6-j];
while(scanf("%d", &a[0]) == 1 && a[0]) {
for(int i = 1; i < 24; i++) scanf("%d", &a[i]);
for(int i = 0; i < 24; i++) if(!a[i]) return 0;
if(is_final()) {
printf("No moves needed\n");
} else {
for(int maxd = 1; ; maxd++)
if(dfs(0, maxd)) break;
}
printf("%d\n", a[6]);
}
return 0;
}