版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/84428319
思路分析:
考虑使用IDA*, 设当前格局(棋盘)中心区域出现次数最多的数的出现次数为m, 显然m <= 8, 易知每次旋转变换至多使得m的值增加1, 因此将8 - m作为估价函数. 基于此策略给出如下AC代码:
//POJ2286_The Rotation Game
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int lpos[7] = {1, 3, 7, 12, 16, 21, 23}, rpos[7] = {2, 4, 9, 13, 18, 22, 24}
, upos[7] = {5, 6, 7, 8, 9, 10, 11}, dpos[7] = {14, 15, 16, 17, 18, 19, 20};
struct State{
char l[8], r[8], u[8], d[8];
//根据输入数组arr初始化l, r, u, d, arr[1]为第一个有效元素
void init(const int *arr){
for(int i = 0; i < 7; ++i)
l[i + 1] = arr[lpos[i]], r[i + 1] = arr[rpos[i]]
, u[i + 1] = arr[upos[i]], d[i + 1] = arr[dpos[i]];
}
//返回中间出现次数最多的元素的出现次数
int f() const{
int arr[4]; memset(arr, 0, sizeof(arr));
for(int i = 3; i <= 5; ++i) ++arr[l[i]], ++arr[r[i]]; ++arr[u[4]], ++arr[d[4]];
int res = 0; for(int i = 1; i <= 3; ++i) res = max(res, arr[i]); return 8 - res;
}
//根据dir(为A, B, C, D, E, F, G或H)执行对应的旋转操作
void move(char dir){
if(dir == 'A') moveHelp(l, true, u, d, 3, 3, 5);
else if(dir == 'B') moveHelp(r, true, u, d, 5, 3, 5);
else if(dir == 'C') moveHelp(u, false, l, r, 3, 3, 5);
else if(dir == 'D') moveHelp(d, false, l, r, 5, 3, 5);
else if(dir == 'E') moveHelp(r, false, u, d, 5, 3, 5);
else if(dir == 'F') moveHelp(l, false, u, d, 3, 3, 5);
else if(dir == 'G') moveHelp(d, true, l, r, 5, 3, 5);
else moveHelp(u, true, l, r, 3, 3, 5);
}
//将a(为l, r, u或d)左移(left为true)或右移(left为false), 并将b[bcpos]赋值为a[abpos],
//将c[bcpos]赋值为a[acpos]
void moveHelp(char *a, bool left, char *b, char *c, int bcpos, int abpos, int acpos){
char arr[16]; int si = sizeof(char) * 7;
memcpy(arr + 1, a + 1, si), memcpy(arr + 8, a + 1, si);
if(!left) memcpy(a + 1, arr + 7, si); else memcpy(a + 1, arr + 2, si);
b[bcpos] = a[abpos], c[bcpos] = a[acpos];
}
};
int rp[200], deep, resNum; vector<char> respath;
const char rdir[8] = {'A', 'F', 'B', 'E', 'C', 'H', 'D', 'G'};
bool dfs(const State &sta, vector<char> &path){
int f = sta.f();
if(path.size() + f > deep) return false;
if(!f){
resNum = sta.l[3], respath = path;
return true;
}
for(int i = 'A'; i <= 'H'; ++i){
if(!path.empty() && (rp[path.back()] ^ 1) == rp[i]) continue;
State tmp = sta; tmp.move(i), path.push_back(i);
if(dfs(tmp, path)) return true;
path.pop_back();
}
return false;
}
int main(){
int arr[25];
rp['A'] = 0, rp['F'] = 1, rp['B'] = 2, rp['E'] = 3
, rp['C'] = 4, rp['H'] = 5, rp['D'] = 6, rp['G'] = 7;
while(scanf("%d", &arr[1]), arr[1]){
for(int i = 2; i <= 24; ++i) scanf("%d", &arr[i]);
State beg; beg.init(arr);
if(!beg.f()){
cout << "No moves needed" << endl << (int)beg.l[3] << endl; continue;
}
vector<char> path; deep = 0, respath.clear();
while(path.clear(), !dfs(beg, path)) ++deep;
for(int i = 0; i < respath.size(); ++i) cout << respath[i]; cout << endl;
cout << resNum << endl;
}
return 0;
}