题目大意:
有一个井字形结构的图形,每条线上7个数字(1,2,3,),每次可以从八个方向将一条线上的数字循环移动1个距离,问经过最少几次什么操作,可以将图形中间的八个方块变成同一种数字。
解题思路:
使用IDA*进行搜索,估价函数为中间八个方块中,不是最多的数字的个数和。
注意点:
题目的输入和存储都不直观,需要十分细心。
代码:
#include <iostream>
using namespace std;
int line1[7],line2[7],row1[7],row2[7];
int step,ans[10000];
bool flag;
//输入
bool input(){
int i;
cin >> row1[0];
if(row1[0] == 0) return false;
cin >> row2[0];
cin >> row1[1] >> row2[1];
for(i = 0; i < 7; i++){
cin >> line1[i];
}
row1[2] = line1[2];
row2[2] = line1[4];
cin >> row1[3] >> row2[3];
for(i = 0; i < 7; i++){
cin >> line2[i];
}
row1[4] = line2[2];
row2[4] = line2[4];
cin >> row1[5] >> row2[5];
cin >> row1[6] >> row2[6];
return true;
}
//循环移动
void circle(int a[7],int direction){
int i,temp;
if(direction == -1){
temp = a[0];
for(i = 1; i < 7; i ++) a[i-1] = a[i];
a[6] = temp;
}
else{
temp = a[6];
for(i = 6; i > 0; i --) a[i] = a[i-1];
a[0] = temp;
}
return;
}
//移动
void moveDirec(int direction){
if(direction == 0){//A操作
circle(row1,-1);
line1[2] = row1[2];
line2[2] = row1[4];
return;
}
if(direction == 1){//B操作
circle(row2,-1);
line1[4] = row2[2];
line2[4] = row2[4];
return;
}
if(direction == 2){//C操作
circle(line1,1);
row1[2] = line1[2];
row2[2] = line1[4];
return;
}
if(direction == 3){//D操作
circle(line2,1);
row1[4] = line2[2];
row2[4] = line2[4];
return;
}
if(direction == 4){//E操作
circle(row2,1);
line1[4] = row2[2];
line2[4] = row2[4];
return;
}
if(direction == 5){//F操作
circle(row1,1);
line1[2] = row1[2];
line2[2] = row1[4];
return;
}
if(direction == 6){//G操作
circle(line2,-1);
row1[4] = line2[2];
row2[4] = line2[4];
return;
}
if(direction == 7){//H操作
circle(line1,-1);
row1[2] = line1[2];
row2[2] = line1[4];
return;
}
}
//反移动
void moveBack(int direction){
if(direction == 0) moveDirec(5);
if(direction == 1) moveDirec(4);
if(direction == 2) moveDirec(7);
if(direction == 3) moveDirec(6);
if(direction == 4) moveDirec(1);
if(direction == 5) moveDirec(0);
if(direction == 6) moveDirec(3);
if(direction == 7) moveDirec(2);
}
//计算中间数字的种类等
int countKind(int &maxBlock,int &blockNum){
int i,num[4] = {0},k = 1,kind = 0;
for(i = 2; i <= 4; i++){
num[line1[i]] ++;
}
num[row1[3]] ++;
num[row2[3]] ++;
for(i = 2; i <= 4; i++){
num[line2[i]] ++;
}
if(num[1] != 0) kind ++;
if(num[2] != 0) kind ++;
if(num[3] != 0) kind ++;
if(num[k] < num[2]) k = 2;
if(num[k] < num[3]) k = 3;
maxBlock = k;
blockNum = num[k];
return kind;
}
int block;
void dfs(int floor){
int i,kind,maxBlock,blockNum;
kind = countKind(maxBlock,blockNum);
if(kind == 1){
block = maxBlock;
flag = true;
return;
}
if(floor >= step) return;
if(floor + (8 - blockNum) > step) return;
for(i = 0; i < 8; i++){
moveDirec(i);
ans[floor] = i;
dfs(floor + 1);
moveBack(i);
if(flag == true) return;
}
return;
}
int main()
{
int maxBlock,blockNum;
while(input()){
if(countKind(maxBlock,blockNum) == 1){
cout << "No moves needed" << endl;
cout << maxBlock << endl;
continue;
}
step = 0;
flag = false;
while(flag == false){
step ++;
dfs(0);
}
char ch;
for(int i = 0; i < step; i++){
ch = 'A' + ans[i];
cout << ch;
}
cout << endl;
cout << block << endl;
}
return 0;
}