聪明的打字员

来源:互联网 发布:双轨对碰无限代算法 编辑:程序博客网 时间:2024/05/01 04:34
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

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!!!

原创粉丝点击