给定一个井字的图形,A-H操作,最少经过几次操作可以将中间8个变成一样的数字
//对于A—H的操作处理得很巧妙
//而且还有reverse操作,可以将mp转换到原来的样子
//启发函数h()
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 24;
const int checkp[] = {6,7,8,11,12,15,16,17};
int line[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}
};
const int rev[] = {5,4,7,6,1,0,3,2};
int mp[maxn];
char ans[maxn];
int maxd = 0;
bool check()
{
int ch = mp[checkp[0]];
for (int i = 0; i < 8; i ++) {
if(mp[checkp[i]] != ch) {return false;}
}
return true;
}
void mov_mp(int op)
{
int tmp = mp[line[op][0]];
for (int i = 0; i < 6; i ++) {
mp[line[op][i]] = mp[line[op][i + 1]];
}
mp[line[op][6]] = tmp;
}
int diff(int ch)
{
int cnt = 0;
for (int i = 0; i < 8; i ++) {
if(mp[checkp[i]] != ch) cnt ++;
}
return cnt;
}
int h()
{
return min(diff(1),min(diff(2),diff(3)));
}
bool dfs(int d)
{
if(maxd == d){
if(!check()) return false;
ans[d] = '\0';
return true;
}
if(d + h() > maxd) return false;
for (int i = 0; i < 8; i ++) {
ans[d] = char(i + 'A');
mov_mp(i);
if(dfs(d + 1)) return true;
mov_mp(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",&mp[0]) == 1 && mp[0]) {
for (int i = 1; i < maxn; i ++) {
scanf("%d",&mp[i]);
}
if(check())
{
printf("No moves needed\n");
printf("%d\n",mp[checkp[0]]);
}
else {
for (maxd = 1; ; maxd ++) {
if(dfs(0)) break;
}
printf("%s\n",ans);
printf("%d\n",mp[checkp[0]]);
}
}
return 0;
}
本文介绍了一种解决井字游戏问题的高效算法,通过A-H操作将棋盘上中间8个位置变为统一数字,利用启发式函数优化搜索过程,实现最少步数的计算。
1642

被折叠的 条评论
为什么被折叠?



