• 【NOI2001】聪明的打字员


    题目

    时间限制: 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);
    }
  • 相关阅读:
    Linux下常用命令以及应用场景
    Java通过代理访问网络的几种方法
    Linux下模拟Http发送的Get和Post请求
    Postgresql常用函数整理
    java-日期Calendar类
    利用数组保存 6 个 Circle 对象,创建 Circle 对象时可传递半径,半 径值由 Math 类的 Random()方法产生( 10 以内,保持一位小数),分别求其面积 (四舍五入,保持两位小数)
    第十讲 Java 资源结构-api
    浅谈面向对象与女娲造人 (摘自 Nerxious)
    java-打印字母表
    java反射机制
  • 原文地址:https://www.cnblogs.com/LinqiongTaoist/p/7203728.html
Copyright © 2020-2023  润新知