大致就是给你一个井字棋的棋盘,每个格子都有1,2或3三种情况,可以往A-H方向移动,问需要最少多少步能让中心的五个变成同一个数。
感觉网上包括刘大佬对这个操作的介绍都很含混,实际上往a移动就是把a方向第一格拿出来放到某位,剩下的往上顶就行。
IDA*。深度就是移动步数。因为每次移动中心位置只会变化一格,所以剪枝为d+h>maxd,d为当前深度,h为中心最少有几个数不同,即最少还要往下几个深度,maxd为当前深度。
在判断的时候,只要判断最少有几个数不同就行
AC代码:
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cstring>
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
*/
int line[10][10]=
{
{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
{23,21,17,12,8,3,1},//E
{22,20,15,11,6,2,0},//F
{13,14,15,16,17,18,19},//G
{4,5,6,7,8,9,10},//H
};
int center[10]={6,7,8,11,12,15,16,17};
int cross[30];
char ans[100];
int check()
{
for(int i=0;i<8;i++)
if(cross[center[0]]!=cross[center[i]]) return 0;
return 1;
}
int predict()
{
int maxx=100;
for(int i=1;i<=3;i++)
{
int a=0;
for (int j=0;j<8;j++) if(cross[center[j]]!=i) a++;
maxx=min(maxx,a);
}
return maxx;
}
int rotate(int mode)
{
int l=cross[line[mode][0]];
for(int i=0;i<6;i++)
cross[line[mode][i]]=cross[line[mode][i+1]];
cross[line[mode][6]]=l;
return 0;
}
int dfs(int d,int maxd)
{
if(d==maxd) return check();
if(d+predict()>maxd) return 0;
for(int i=0;i<8;i++)
{
ans[d]=i+'A';
rotate(i);
if(dfs(d+1,maxd)) return 1;
if(i%2==0) rotate((i+5)%8);
else rotate((i+3)%8);
}
return 0;
}
int main()
{
while(cin>>cross[0]&&cross[0])
{
for(int i=1;i<24;i++)
cin>>cross[i];
if(check()) cout<<"No moves needed\n";
else
{
int i=0;
while(++i)
if(dfs(0,i)) break;
ans[i]='\0';
cout<<ans<<endl;
}
cout<<cross[center[0]]<<endl;
}
return 0;
}