题目:https://www.acwing.com/problem/content/183/
如下图所示,有一个“#”形的棋盘,上面有1,2,3三种数字各8个。
给定8种操作,分别为图中的A~H。
这些操作会按照图中字母和箭头所指明的方向,把一条长为8的序列循环移动1个单位。
例如下图最左边的“#”形棋盘执行操作A后,会变为下图中间的“#”形棋盘,再执行操作C后会变成下图最右边的“#”形棋盘。
给定一个初始状态,请使用最少的操作次数,使“#”形棋盘最中间的8个格子里的数字相同。
输入格式
输入包含多组测试用例。
每个测试用例占一行,包含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
题解: 这道题我们考虑搜索,但是由于状态较多,需要一些优化:1.每次枚举操作时,我们不考虑与上次操作产生抵消效果的操作。2.每次我们考虑一个函数,如果cnt+f()> step,也就是无法在step前完成,直接回溯。另外,由于操作本身比较复杂,我们将操作和操作的数的下标进行编号,这样可以简化代码。
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,b,a) for(int i=b;i>=a;i--)
#define Mst(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&-x
const int N = 105;
int op[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[] = {5,4,7,6,1,0,3,2};
int center[] = {6,7,8,11,12,15,16,17};
int path[N],a[N];
int f() {
int sum[4] = {0};
int maxn = 0;
rep(i,0,7) {
sum[a[center[i]]]++;
}
rep(i,1,3) maxn = max(maxn,sum[i]);
return 8-maxn;
}
void make(int x) {
int t = a[op[x][0]];
rep(i,0,5) a[op[x][i]] = a[op[x][i+1]];
a[op[x][6]] = t;
}
bool dfs(int cnt,int step,int last) {
if(cnt + f() > step) return false;
if(f() == 0) return true;
rep(i,0,7) {
if(opposite[i] == last) continue;
path[cnt] = i;
make(i);
if(dfs(cnt+1,step,i)) return true;
make(opposite[i]);
}
return false;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
while(cin >> a[0] && a[0]) {
rep(i,1,23) cin >> a[i];
int step = 0;
while(!dfs(0,step,-1)) step++;
if(!step) {
cout << "No moves needed" << endl;
cout << a[center[0]] << endl;
}
else {
rep(i,0,step-1) cout << (char)(path[i] + 'A');
cout << endl;
cout << a[center[0]] << endl;
}
}
return 0;
}