题目: LINK
通过给定的六种操作将一个六位数变为另一个六位数,求需要的最少操作数。
六种操作:
左移和右移:将光标位置左移一位或右移一位,在第一位时无法左移,最后一位时无法右移。
左交换和右交换:将光标位置的数字与第一位或最后一位交换
增大或减小:将光标位置的数字增大或减小1
最容易想到的做法是直接BFS,6*1000000 个状态,妥妥TLE。
可以把六种操作分成两种,一种是左右移和左右交换,另一种是增加减小。为什么区分为两种?
因为,我们可以先进行第一种操作, 只有位置交换和光标移动,不会有数值的变化,所以我们可以BFS遍历出来所有的位置组合6!和每种下的光标经历的情况.
对于光标经历过的位置的情况有一下10种.
1
1,2
1,2,3
1,2,3,4
1,2,3,4,5
1,6
1,2,6
1,2,3,6
1,2,3,4,6
1,2,3,4,5,6
所以状态是6*6!*10.是可以接受的,而且这一步可以预处理出来, 与出入的数据无关.
对于这儿6!,可以直接用6进制进行处理,当然也可以利用康托展开进行HASH。
对于分离出来的第二种操作,由第一种的状态,如果某一位光标经历过(与什么时候经历的无关),那么它的值可以改变,改变的大小就是这一位两者先后的差值.
对于第一种得出的所有的状态算出最小的移动次数就好了.
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define INF 1000000000
//typedef __int64 LL;
struct node {
int num[7], has, th, step;
};
bool vis[51111][12][7];
char s1[10], s2[10];
vector<node > save;
int ha[10], T[10];
int get(int num[]) {
int ret = 0;
for(int i = 0; i < 6; i++) {
ret *= 6; ret += num[i];
}
return ret;
}
void change(node &in, int ii) {
if(ii == 0) {//left move
if(in.th) in.th --;
}
else if(ii == 1) {//right move
if(in.th != 5) in.th ++;
if(in.th == 5) {
if(in.has <= 4) in.has += 5;
}
else {
if(in.has <=4 && in.th > in.has) in.has ++;
if(in.has >=5 && in.th > in.has - 5) in.has ++;
}
}
else if(ii == 2) { //left swap
swap(in.num[0], in.num[in.th]);
}
else if(ii == 3) {//right swap
swap(in.num[5], in.num[in.th]);
if(in.has < 5) in.has += 5;
}
in.step ++;
}
void bfs() {
queue< node > Q;
save.clear();
memset(vis, 0, sizeof(vis));
node now, next;
for(int i = 0; i < 6; i++) now.num[i] = i;
now.has = 0; now.th = 0; now.step = 0;
vis[get(now.num)][now.has][now.th] = 1;
Q.push(now);
while(!Q.empty()) {
now = Q.front(); Q.pop();
save.push_back(now);
for(int i = 0; i < 4; i++) {
next = now;
change(next, i);
int tmp = get(next.num);
if(vis[tmp][next.has][next.th]) continue;
vis[tmp][next.has][next.th] = 1;
Q.push(next);
}
}
}
void sol() {
int ret = INF;
for(int i = 0; i < save.size(); i++) {
int flag = 0,sum = 0;
int tt = save[i].has;
if(tt > 4) tt -= 5;
for(int j= 0; j < 6; j++) {
int dd = 0;
if(j <= 4 && j <= tt) dd = 1;
else if(j == 5 && save[i].has >= 5) dd = 1;
int pre = save[i].num[j];
if(dd == 1 ) sum += abs(s1[pre] - s2[j]) ;
else if(dd == 0 && s1[pre] != s2[j]) {
flag = 1; break;
}
}
if(!flag) ret = min(ret, save[i].step + sum);
}
printf("%d\n", ret);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
bfs();
while(scanf("%s%s", s1, s2) != EOF) {
for(int i = 0; i < 6; i++) s1[i] -= '0', s2[i] -= '0';
sol();
}
return 0;
}