题目大意:
输入区有六个数字和一个光标(光标开始时位于第一个数),使用以下六种操作将其变为目标数字,求最少操作数:
1.Swap0:将光标所在数字和第一个数交换
2.Swap1:将光标所在数字和最后一个数交换
3.Up:给光标所在数字+1
4.Down:给光标所在数字-1
5.Left:光标左移
6.Right:光标右移
分析:
这道题做得很失败,一开始想当然的剪枝,认为2-5的四个数字只要和目标数字不同,就没必要移动光标,居然还A了。。数据太水。后来看一个dalao博客给出的一组数据,000159 000519,最小操作数是8,即交换19、51、95,光标是可以移动的嘛!
正解:
将操作分为两类,只有Up/Down可以改变数字的值,剩下四种操作实际上只能改变给定数字的相对位置。把六个数字的位置、光标位置和已访问的数字(只有光标访问过的数字才能用Up/Down改变)作为状态,一遍BFS搜出所有可能的组合,再加上与每一位目标数字之差的绝对值的和(即Up/Down次数)就是答案了。
注意:光标的访问状态只有十种,第一位一定会被访问,而且只有Right和Swap1可以访问未访问过的位置
代码:
#include <iostream>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
bool vis[6][6][6][6][6][6][6][10] = {0};//0-5分别对应输入区6个数字的位置,6表示光标位置,7表示光标访问状态
bool list[10][6] = {{1,0,0,0,0,0},//只有Right或Swap1可以访问未访问过的位置,所以只有10种访问状态
{1,0,0,0,0,1},
{1,1,0,0,0,0},
{1,1,0,0,0,1},
{1,1,1,0,0,0},
{1,1,1,0,0,1},
{1,1,1,1,0,0},
{1,1,1,1,0,1},
{1,1,1,1,1,0},
{1,1,1,1,1,1}};
struct node{//分别是 光标位置,访问状态,步数,6个数字的位置
int pos; int state; int d; vector<int> n;
};
int main(){
int i, j, a[6] = {0}, b[6] = {0}, ts, min = 0x7FFFFFFF, r;
string sa, sb;
cin >> sa >> sb;
for (i = sa.size()-1, j = 5; i >= 0; i--, j--) a[j] = sa[i]-'0';
for (i = sb.size()-1, j = 5; i >= 0; i--, j--) b[j] = sb[i]-'0';
queue<node> q;
int init[6] = {0, 1, 2, 3, 4, 5};
vector<int> t;
q.push((node){0, 0, 0, vector<int>(init, init+6)});
vis[0][1][2][3][4][5][0][0] = 1;
while (!q.empty()){
node f = q.front();
q.pop();
//根据当前状态计算所需Up/Down次数
r = f.d;
for (i = 0; i < 6; i++){
if (list[f.state][i]) r += fabs(a[f.n[i]]-b[i]);
else if (a[f.n[i]] != b[i]){
r = 0x7FFFFFFF;
break;
}
}
if (r < min) min = r;
//Swap0
t = f.n;
t[0] = f.n[f.pos];//交换
t[f.pos] = f.n[0];
if (!vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos][f.state]){
q.push((node){f.pos, f.state, f.d+1, t});
vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos][f.state] = 1;
}
//Swap1
t = f.n;
t[5] = f.n[f.pos];//交换
t[f.pos] = f.n[5];
if (f.state % 2 == 0) ts = f.state+1;//访问到最后一个数
else ts = f.state;
if (!vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos][ts]){
q.push((node){f.pos, ts, f.d+1, t});
vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos][ts] = 1;
}
//Left
t = f.n;
if (f.pos > 0 && !vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos-1][f.state]){
q.push((node){f.pos-1, f.state, f.d+1, f.n});
vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos-1][f.state] = 1;
}
//Right
t = f.n;
if (f.state <= 6) ts = f.state+2;//访问到下一个数
else ts = 9;
if (f.pos < 5 && !vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos+1][ts]){
q.push((node){f.pos+1, ts, f.d+1, f.n});
vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos+1][ts] = 1;
}
}
cout << min;
return 0;
}