Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u
Submit
Status
Description
阿兰是某机密部门的打字员,她现在接到一个任务:需要在一天之内输入几百个长度固定为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号位置上。当巧妙地使用上述六个特殊键之后,可以得到目标密码,这时光标允许停在任何一个位置。
现在,阿兰需要你的帮助,编写一个程序,求出录入一个密码需要的最少的击键次数。
Input
仅一行,含有两个长度为6的数,前者为初始密码,后者为目标密码,两个密码之间用一个空格隔开。
Output
仅一行,含有一个正整数,为最少需要的击键次数。
Sample Input
123456 654321
Sample Output
Submit
Status
Description
阿兰是某机密部门的打字员,她现在接到一个任务:需要在一天之内输入几百个长度固定为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号位置上。当巧妙地使用上述六个特殊键之后,可以得到目标密码,这时光标允许停在任何一个位置。
现在,阿兰需要你的帮助,编写一个程序,求出录入一个密码需要的最少的击键次数。
Input
仅一行,含有两个长度为6的数,前者为初始密码,后者为目标密码,两个密码之间用一个空格隔开。
Output
仅一行,含有一个正整数,为最少需要的击键次数。
Sample Input
123456 654321
Sample Output
11
解题思路:
刚开始做的时候才用普通的宽搜,仅仅加了一个判重的优化,经过一些列细节改正后,
果断超时。。。
后来,在网上找到了经过大幅度优化过的bfs,其最经典的是先模拟出所有的状态
(这个状态只包括每一位的位置,不管大小),因此,每个状态需要记录每个位置的坐标(s数组),
经过了哪些位置(size),当前位置(cur),到达此状态需要的步数(sum)
其中,s数组只需要将012345这些代表下标的数进行变换,size有10种情况,对应于sign数组的预
处理中的数,这个需要仔细去体会与验算,我当初就是想了很久。
然后就是利用队列和vis判重通过那四种只改变下标的方式转换状态,用ans记下可行状态。
接下来,在main函数中,将每一种状态转变成实数与最终目的进行比较,如果每一位都相等或者经过该下标
则是可行方案,利用ans[i][7]和abs[b[j]-a[ans[i][j]]]求出step的大小,并进行比较,把最小值给min,
最后输出min就行了。
有些人认为不需要考虑左移的情况,这种想法有问题,000159 和 000519 就是一特例,这里已解决这个问题!!!
源程序:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<queue>
using namespace std;
typedef struct
{
int s[6];
int size,sum,cur;
}node; //状态转换时需要用到的中间状态
bool vis[6][6][6][6][6][6][6][10]={false}; //判重数组
int sign[10][6]={{1,0,0,0,0,0},
{1,1,0,0,0,0},
{1,1,1,0,0,0},
{1,1,1,1,0,0},
{1,1,1,1,1,0},
{1,1,1,1,1,1},
{1,0,0,0,0,1},
{1,1,0,0,0,1},
{1,1,1,0,0,1},
{1,1,1,1,0,1}
}; //10种表示经过哪些位置的预处理,仔细想想
int total=0,ans[8605][8]; //ans存储可行状态,8605可由输出total得到
void bfs() //bfs模拟出所有可行状态
{
int i;
node a;
for (i=0;i<6;i++)
{
a.s[i]=i;
}
a.size=0; a.cur=0; a.sum=0;
vis[a.s[0]][a.s[1]][a.s[2]][a.s[3]][a.s[4]][a.s[5]][a.cur][a.size]=true; //初始化
queue<node>sq;
sq.push(a); //利用队列来控制状态的转换
while (!sq.empty())
{
a=sq.front();
sq.pop();
for (i=0;i<6;i++)
{
ans[total][i]=a.s[i];
}
ans[total][6]=a.size;
ans[total][7]=a.sum; //将队首状态给ans
total++;
a.sum++;
if (a.cur>0) //下标与0换 和 左移
{
swap(a.s[0],a.s[a.cur]);
if (!vis[a.s[0]][a.s[1]][a.s[2]][a.s[3]][a.s[4]][a.s[5]][a.cur][a.size])
{
vis[a.s[0]][a.s[1]][a.s[2]][a.s[3]][a.s[4]][a.s[5]][a.cur][a.size]=true;
sq.push(a);
}
swap(a.s[a.cur],a.s[0]);
a.cur--;
if (!vis[a.s[0]][a.s[1]][a.s[2]][a.s[3]][a.s[4]][a.s[5]][a.cur][a.size])
{
vis[a.s[0]][a.s[1]][a.s[2]][a.s[3]][a.s[4]][a.s[5]][a.cur][a.size]=true;
sq.push(a);
}
a.cur++;
}
if (a.cur<5) //下标与5换 和 右移
{
int temp=a.size;
a.cur++;
if (a.cur>a.size||(a.cur>a.size-6&&a.size>5))
{
if (a.size==9) a.size=5;
else a.size++;
}
if (!vis[a.s[0]][a.s[1]][a.s[2]][a.s[3]][a.s[4]][a.s[5]][a.cur][a.size])
{
vis[a.s[0]][a.s[1]][a.s[2]][a.s[3]][a.s[4]][a.s[5]][a.cur][a.size]=true;
sq.push(a);
}
a.cur--;
a.size=temp;
if (a.size<4) a.size+=6;
swap(a.s[a.cur],a.s[5]);
if (!vis[a.s[0]][a.s[1]][a.s[2]][a.s[3]][a.s[4]][a.s[5]][a.cur][a.size])
{
vis[a.s[0]][a.s[1]][a.s[2]][a.s[3]][a.s[4]][a.s[5]][a.cur][a.size]=true;
sq.push(a);
}
}
}
}
int abs(int x)
{
if (x<0) return -x;
else return x;
}
int main()
{
int a[6],b[6],i,step,j;
char s[7],t[7];
int min=20112011;
bfs();
scanf("%s%s",s,t);
for (i=0;i<6;i++)
{
a[i]=s[i]-'0';
b[i]=t[i]-'0';
}
for (i=0;i<total;i++)
{
step=ans[i][7];
for (j=0;j<6;j++)
if (b[j]!=a[ans[i][j]]&&!sign[ans[i][6]][j]) break;
else step+=abs(b[j]-a[ans[i][j]]);
if ((min>step)&&j==6)
{
min=step;
}
}
printf("%d\n",min);
return 0;
}
预祝早日AC!!!