题目
时间限制: 5 Sec 内存限制: 128 MB
题目描述
阿兰是某机密部门的打字员,她现在接到一个任务:需要在一天之内输入几百个长度固定为6的密码。当然,她希望输入的过程中敲击键盘的总次数越少越好。
不幸的是,出于保密的需要,该部门用于输入密码的键盘是特殊设计的,键盘上没有数字键,而只有以下六个键:Swap0, Swap1, Up, Down, Left, Right,为了说明这6个键的作用,我们先定义录入区的6个位置的编号,从左至右依次为1,2,3,4,5,6。下面列出每个键的作用:
Swap0:
按Swap0,光标位置不变,将光标所在位置的数字与录入区的1号位置的数字(左起第一个数字)交换。如果光标已经处在录入区的1号位置,则按Swap0键之后,录入区的数字不变;
Swap1:
按Swap1,光标位置不变,将光标所在位置的数字与录入区的6号位置的数字(左起第六个数字)交换。如果光标已经处在录入区的6号位置,则按Swap1键之后,录入区的数字不变;
Up:
按Up,光标位置不变,将光标所在位置的数字加1(除非该数字是9)。例如,如果光标所在位置的数字为2,按Up之后,该处的数字变为3;如果该处数字为9,则按Up之后,数字不变,光标位置也不变;
Down:
按Down,光标位置不变,将光标所在位置的数字减1(除非该数字是0),如果该处数字为0,则按Down之后,数字不变,光标位置也不变;
Left:
按Left,光标左移一个位置,如果光标已经在录入区的1号位置(左起第一个位置)上,则光标不动;
Right:
按Right,光标右移一个位置,如果光标已经在录入区的6号位置(左起第六个位置)上,则光标不动。
当然,为了使这样的键盘发挥作用,每次录入密码之前,录入区总会随机出现一个长度为6的初始密码,而且光标固定出现在1号位置上。当巧妙地使用上述六个特殊键之后,可以得到目标密码,这时光标允许停在任何一个位置。
现在,阿兰需要你的帮助,编写一个程序,求出录入一个密码需要的最少的击键次数。
输入
文件仅一行,含有两个长度为6的数,前者为初始密码,后者为目标密码,两个密码之间用一个空格隔开。
样例输出
123456 654321
样例输出
11
思路
只有6位数,时间还一大把,直接广搜,写一个结构体,包含有swap0等一系列函数,使广搜函数更简洁,7维数组vis(还有光标的位置)判重即可。
代码
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
int ans;
bool vis[10][10][10][10][10][10][10];
struct lock
{
int a[7];//当前密码
int sum,cur;//sum是步数
void operator = (int x)//重载赋值号,方便读入
{
int bit[7]={0,100000,10000,1000,100,10,1};
for(int i=1;i<=6;i++)
a[i]=x/bit[i]%10;
cur=1;//光标位置
}
bool operator == (lock x)//重载逻辑等于
{
for(int i=1;i<=6;i++)
if(a[i]!=x.a[i])
return 0;
return 1;
}
void swap0(){swap(a[1],a[cur]);sum++;}
void swap1(){swap(a[6],a[cur]);sum++;}
void up(){a[cur]++;sum++;}
void down(){a[cur]--;sum++;}
void left(){cur--;sum++;}
void right(){cur++;sum++;}//六个键
}s,e;//开始时的密码和目标密码
queue<lock> q;
bool check(lock x)//判断是否完成(如果没有完成就标记当前情况)
{
if(x==e){ans=x.sum;return 1;}
if(!vis[x.a[1]][x.a[2]][x.a[3]][x.a[4]][x.a[5]][x.a[6]][x.cur])
{
vis[x.a[1]][x.a[2]][x.a[3]][x.a[4]][x.a[5]][x.a[6]][x.cur]=1;
q.push(x);
}
return 0;
}
void bfs()
{
q.push(s);
vis[s.a[1]][s.a[2]][s.a[3]][s.a[4]][s.a[5]][s.a[6]][s.cur]=1;//标记最开始的情况
while(!q.empty())
{
lock t;
t=q.front();
if(t.cur>1)
{
t.swap0();
if(check(t)) break;
t=q.front();
t.swap0();
if(check(t)) break;
}
t=q.front();
if(t.cur<6)
{
t.swap1();
if(check(t)) break;
t=q.front();
t.right();
if(check(t)) break;
}
t=q.front();
if(t.a[t.cur]<9)
{
t.up();
if(check(t)) break;
}
t=q.front();//注意每个键按了后密码就不一样了,所以要重新front一次
if(t.a[t.cur]>0)
{
t.down();
if(check(t)) break;
}//枚举6个键
q.pop();
}
}
int main()
{
int x,y;
scanf("%d%d",&x,&y);
if(x==y){printf("0");return 0;}
s=x; e=y;
bfs();
printf("%d",ans);
}