现在的位置: 首页 > 综合 > 正文

聪明的打字员

2013年04月29日 ⁄ 综合 ⁄ 共 3612字 ⁄ 字号 评论关闭

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

【上篇】
【下篇】

抱歉!评论已关闭.