Description
(简化版)只输出操作次数,不用输出方案。
Solution
直接爆搜?显然复杂度会炸。
考虑优化,我们想到 (IDA*)(迭代加深搜索),这篇博客默认你已经会了这个算法,如果还不会的话可以去网上搜一下。
不难发现,本题的乐观估价函数为 (8 - cnt)(中间 8 个数中出现次数最多的数的个数)
如果这个值加上我们已经走了的步数大于当前预期的步数,那么直接 (return)。
反之继续搜索。
Code
我把这个 井 字,存到了 8 * 8 的数组中。
在 (update) (即操作)时,循环赋值。
(非常丑陋)
#include <iostream>
#include <cstdio>
#define ri register int
using namespace std;
const int N = 10;
int a[N][N];
int cnt;
int arc[8] = {5, 4, 7, 6, 1, 0, 3, 2};//回溯用的,为了反着操作一遍
inline int check(){//乐观估价函数
int t[5] = {0};
for(ri i = 3; i <= 5; i++)
for(ri j = 3; j <= 5; j++)
t[a[i][j]]++;
ri maxs = 0;
maxs = max(max(t[1], t[2]), t[3]);
return 8 - maxs;
}
inline void solve_row(int row, int k){//列上操作
if(k < 0){
ri res = a[1][row];
for(ri i = 1; i < 7; i++)
a[i][row] = a[i + 1][row];
a[7][row] = res;
}else{
ri res = a[7][row];
for(ri i = 7; i > 1; i--)
a[i][row] = a[i - 1][row];
a[1][row] = res;
}
}
inline void solve_line(int line, int k){//行上操作
if(k < 0){
ri res = a[line][1];
for(ri i = 1; i < 7; i++)
a[line][i] = a[line][i + 1];
a[line][7] = res;
}else{
ri res = a[line][7];
for(ri i = 7; i > 1; i--)
a[line][i] = a[line][i - 1];
a[line][1] = res;
}
}
inline void update(int k){//8 个位置
if(k == 0) solve_row(3, -1);
else if(k == 1) solve_row(5, -1);
else if(k == 2) solve_line(3, 1);
else if(k == 3) solve_line(5, 1);
else if(k == 4) solve_row(5, 1);
else if(k == 5) solve_row(3, 1);
else if(k == 6) solve_line(5, -1);
else if(k == 7) solve_line(3, -1);
}
inline int dfs(int step){
if(step == cnt){
if(!check()) return 1;
return 0;
}
if(check() + step > cnt) return 0;
for(ri i = 0; i < 8; i++){
update(i);
if(dfs(step + 1)) return 1;
update(arc[i]);//要update回来
}
return 0;
}
int main(){
while(scanf("%d", &a[1][3]) && a[1][3]){
scanf("%d%d%d", &a[1][5], &a[2][3], &a[2][5]);
for(int i = 1; i <= 7; i++)
scanf("%d", &a[3][i]);
scanf("%d%d", &a[4][3], &a[4][5]);
for(int i = 1; i <= 7; i++)
scanf("%d", &a[5][i]);
scanf("%d%d%d%d", &a[6][3], &a[6][5], &a[7][3], &a[7][5]);//极其丑陋的初始化
for(cnt = 0; ; cnt++){
if(dfs(0))
break;
}
printf("%d
", cnt);
}
return 0;
}