题面
如下图所示,有一个“#”形的棋盘,上面有1,2,3三种数字各8个。
给定8种操作,分别为图中的A~H。
这些操作会按照图中字母和箭头所指明的方向,把一条长为8的序列循环移动1个单位。
例如下图最左边的“#”形棋盘执行操作A后,会变为下图中间的“#”形棋盘,再执行操作C后会变成下图最右边的“#”形棋盘。
给定一个初始状态,请使用最少的操作次数,使“#”形棋盘最中间的8个格子里的数字相同。
2286_1.jpg
输入格式
输入包含多组测试用例。
每个测试用例占一行,包含24个数字,表示将初始棋盘中的每一个位置的数字,按整体从上到下,同行从左到右的顺序依次列出。
输入样例中的第一个测试用例,对应上图最左边棋盘的初始状态。
当输入只包含一个“0”的行时,表示输入终止。
输出格式
每个测试用例输出占两行。
第一行包含所有移动步骤,每步移动用大写字母“A~G”中的一个表示,字母之间没有空格,如果不需要移动则输出“No moves needed”。
第二行包含一个整数,表示移动完成后,中间8个格子里的数字。
如果有多种方案,则输出字典序最小的解决方案。
输入样例:
1 1 1 1 3 2 3 2 3 1 3 2 2 3 1 2 2 2 3 1 2 1 3 3
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
0
输出样例:
AC
2
DDHH
2
思路
搜索,问最小步数,可以想到bfs和ida,那么我们考虑使用ida,首先的话为了方便我们可以打表然后把二维压成一维去操作,这样比较方便。那么我们这里考虑一下估价函数,目的是要*那一圈数字一样,我们进行一次操作会出圈一个数,进圈一个数,那么这样的话我们考虑最优情况,最终状态是原先数字最多的,那么我们可以用最少的操作数得到结果,所以估价函数为8-最多的数字的数量,然后就直接写ida的框架就好了。这里总结一个ida,总而言之最重要的还是一个估价函数的设计,估价函数怎么寻找,我们要尽量去往操作对最终结果的影响上去想,然后取一个最优的情况做为估价函数就好了。
代码实现
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#include<stack>
using namespace std;
const int maxn=24;
int option[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}
};
int opposite[8]={5,4,7,6,1,0,3,2};
int center[8]={6,7,8,11,12,15,16,17};
int q[maxn];
int path[100];
int f () {
static int sum[4];
memset (sum,0,sizeof (sum));
for (int i=0;i<8;i++) {
sum[q[center[i]]]++;
}
int s=0;
for (int i=1;i<=3;i++) {
s=max (s,sum[i]);
}
return 8-s;
}
bool check () {
for (int i=0;i<8;i++)
if (q[center[i]]!=q[center[0]]) return false;
return true;
}
void oper (int x) {
int t=q[option[x][0]];
for (int i=0;i<6;i++) q[option[x][i]]=q[option[x][i+1]];
q[option[x][6]]=t;
}
bool dfs (int deep,int maxdeep,int last) {
if (deep+f()>maxdeep) return false;
if (check ()) return true;
for (int i=0;i<8;i++) {
if (opposite[i]==last) continue;
oper (i);
path[deep]=i;
if (dfs (deep+1,maxdeep,i)) return true;
oper (opposite[i]);
}
return false;
}
int main () {
while (cin>>q[0]&&q[0]) {
for (int i=1;i<maxn;i++) {
cin>>q[i];
}
int deepth=0;
while (!dfs (0,deepth,-1)) deepth++;
if (!deepth) cout<<"No moves needed";
else {
for (int i=0;i<deepth;i++) printf ("%c",path[i]+'A');
}
printf ("\n%d\n",q[6]);
}
return 0;
}