zoukankan      html  css  js  c++  java
  • 【8001】输入密码

    Time Limit: 3 second
    Memory Limit: 2 MB

    【问题描述】

        John是某部门的工作人员,为提升安全等级,该部门的密码键盘是特殊设计的,键盘上没有数字按键, 而只有六个按键:
    Up,Down,Left,Right,Sw0,Sw1,定义录入区域的六个位置的编号,从左至右依次为1,2,3,4,5,6。下面列出每个键的作用:
    
       Sw0:按Sw0,光标位置不变,将光标所在位置上的数字与录入区的1号位置上的数字交换。如果光标已经处在录入区
    的1号位置,则按Sw0键之后,录入区的数字不变;
      Sw1:按Sw1,光标位置不变,将光标所在位置上的数字与录入区的6号位置上的数字交换。如果光标已经处在录入区
    的6号位置,则按Sw1键之后,录入区的数字不变;
      Up:按Up,光标位置不变,将光标所在位置上的数字加1(除非该数字是9)。例如,如果光标所在位置的数字为2,按Up之后,
    该处的数字变为3;如果该处数字为9,则按Up之后,数字不变,光标位置也不变;
      Down:按Down,光标位置不变,将光标所在位置上的数字减1(除非该数字是0),如果该处数字为0,则按Down之后,数字
    不变,光标位置也不变;
      Left:按Left,光标左移一个位置,如果光标已经停留在录入区的1号位置(左起第一个位置)上,则光标不动;
      Right:按Right,光标右移一个位置,如果光标已经停留在录入区的6号位置(左起第六个位置)上,则光标不动。
    
      当然,为了使这样的键盘能够发挥作用,在每次开始要录入密码之前,录入区总是会随机出现一串长度为6的初始密码,
    光标首先停留在1号位置上,当你巧妙地操作使用上述6个特殊按键之后,可以得到需要的目标密码,这时光标允许停留在任何
    一个位置。
      现在,John有一个6位的数字密码,请编写一个程序,求出录入一个指定的密码需要的最少的操作击键次数。 
    

    【输入】

    输入数据为一行, 两个六位的数字, 之间用空格隔开。
    第一个数据是指录入区上的初始数字(6位), 后加空格, 第二个为要输入的密码值(6为数字)。
    

    【输出】

    输出一行, 最少的按键次数
    

    【输入样例】

    123456 654321

    【输出样例】

    11


    【题解】

    已知起点求到终点的最少步骤数,广搜问题。这题不能用string类来做,虽然string类很方便,但是经过这一次,我彻底感受到了,string类在运行时有多么缓慢。。。将输入的两个数字先以string类的形式输入,然后把两个string类转换成int数组。用int数组来操作,会快很多。

    然后是判重,用bool型数组bo[1000000][6]来判重,第一维是6位数字,第二维是光标的位置。然后在做广搜的时候用下循环队列,不然会超内存。

    具体的看代码注释。

    【代码】

    #include <cstdio>
    #include <string>
    #include <stdlib.h>
    #include <iostream>
    
    using namespace std;
    
    const int qq = 4500000;
    const int qqq = 4500000+20; //这两个常量是用于循环队列 这个变量可以变成250W,那样占内存会更小。
    
    int a,b,goal;
    string ts1,ts2;
    bool bo[1000000][6];
    int dl1[qqq][6];
    short dl2[qqq],dl3[qqq];
    int s1[6],s2[6];
    
    
    int get_num(int ss[6]) //将int数组转换成单个整形变量
    {
        int l1 = 6,t = 0;
        int i = 0;
        while (i <= l1-1)
            {
                t = t*10 + ss[i];
                i++;
            }
        return t;
    }
    
    void input_data()
    {
        cin >> ts1; //把string类转换成int数组
        cin >> ts2;
        for (int i = 0; i<= 5;i++)
            s1[i] = ts1[i] - '0';
        for (int i = 0;i <= 5;i++)
            s2[i] = ts2[i] - '0';
        goal = get_num(s2); //获取目标数字
        for (int i = 100000;i <= 999999;i++) //一开始把判重数组初始化
            for (int j = 0;j <= 5;j++)
                bo[i][j] = false;
    }
    
    void change(int & a,int & b) //交换数字a和b
    {
        int t = a;
        a = b;
        b = t;
    }
    
    void get_ans() //开始广搜
    {
        int head = 0,tail = 1;
        for (int i = 0;i <= 5;i++)
            dl1[1][i] = s1[i];
        dl2[1] = 0; //步数
        dl3[1] = 0; //光标位置
        int t = get_num(s1);
        bo[t][0] = true;
        while (head != tail) //循环队列不能写成 head <= tail
            {
                head++;
                int temp[6];
                for (int i = 0;i <= 5;i++) //取出队列的头结点
                    temp[i] = dl1[head][i];
                int step = dl2[head],p = dl3[head];
                head = head % qq; //循环队列
                int num0 = get_num(temp); //将这个int数组转换成一个整形
                //和第0个位置上的数字交换
                if (p != 0) //如果光标不在第一位 就和第一位交换位置
                    {
                        change(temp[p],temp[0]);
                        int num1 = get_num(temp); //再转换成数字
                        if (!bo[num1][p]) //判重
                            {
                                if(num1 == goal) //如果获得了目标就输出
                                    {
                                        printf("%d
    ",step+1);
                                        exit(0);
    
                                    }
                                bo[num1][p] = true; //判重
                                tail++; //把这个元素存入队列中  连同光标位置也要存
                                tail = tail %qq;
                                for (int i = 0;i <= 5;i++)
                                    dl1[tail][i] = temp[i];
                                dl2[tail] = step+1; //同时还要存入步骤数。
                                dl3[tail] = p;
                            }
                        change(temp[0],temp[p]); //再把这个元素恢复原状
                    }
    
                //和第5个位置上的数字交换
                if (p != 5) //下列步骤与 交换第0个位置的相同。参考上面的注释
                    {
                        change(temp[p],temp[5]);
                        int numx = get_num(temp);
                        if (!bo[numx][p])
                            {
                                if(numx == goal)
                                    {
                                        printf("%d
    ",step+1);
                                        exit(0);
                                    }
                                bo[numx][p] = true;
                                tail++;
                                tail = tail % qq;
                                for (int i = 0;i <= 5;i++)
                                    dl1[tail][i] = temp[i];
                                dl2[tail] = step+1;
                                dl3[tail] = p;
                            }
                        change(temp[5],temp[p]);
                    }
    
    
                //光标所在位置上的数字+1;
                int temp1[6]; //如果光标位置上的数字是8或9,之后恢复原状会有点麻烦,所以直接对temp1而不是原数字进行操作。
                for (int i = 0;i <= 5;i++)
                    temp1[i] = temp[i];
                if (temp1[p] != 9) //如果光标的数字不是9 那么就把这个数字递增
                    {
                        temp1[p] += 1;
                        int num2 = get_num(temp1); //转成单个整形
                        if (!bo[num2][p]) //判重
                            {
                                if(num2 == goal) //如果等于目标,则输出.
                                    {
                                        printf("%d
    ",step+1);
                                        exit(0);
                                    }
                                bo[num2][p] = true; //判重
                                tail++; //把光标和数字和步骤数的信息存入队列
                                tail = tail %qq;
                                for (int i = 0;i <= 5;i++)
                                    dl1[tail][i] = temp1[i];
                                dl2[tail] = step+1;
                                dl3[tail] = p;
                            }
                    }
    
    
    
                //光标所在位置上的数字-1; 和+1的情形类似,参照上面注释
                for (int i = 0;i <= 5;i++)
                    temp1[i] = temp[i];
                if (temp1[p] != 0)
                    {
                        temp1[p] -= 1;
                        int num3 = get_num(temp1);
                        if (!bo[num3][p])
                            {
                                if (num3 == goal)
                                    {
                                        printf("%d
    ",step+1);
                                        exit(0);
                                    }
                                bo[num3][p] = true;
                                tail++;
                                tail = tail %qq;
                                for (int i = 0;i <= 5;i++)
                                    dl1[tail][i] = temp1[i];
                                dl2[tail] = step+1;
                                dl3[tail] = p;
                            }
                    }
    
                //光标左移一个位置; //因为有光标在0,1位置的情况,左移后都是1 不好还原 所以还是对pp光标进行操作
                int pp = p;
                if (pp != 0) //如果不是最左边 就操作(如果是最左边 操作这一步是没有意义的)
                    {
                        pp--; //光标左移
                        if (!bo[num0][pp]) //判重
                            {
                                bo[num0][pp] = true;
                                tail++; //这次不用判断数字是否是目标,因为移动光标数字不会变的。
                                tail = tail % qq; //把数字和光标信息加入队列.
                                for (int i = 0;i <= 5;i++)
                                    dl1[tail][i] = temp[i];
                                dl2[tail] = step +1;
                                dl3[tail] = pp;
                            }
                    }
    
                //光标右移一个位置
                pp = p;  //和光标左移的情况相同 注释参考上面。
                if (pp != 5)
                    {
                        pp++;
                        if (!bo[num0][pp])
                            {
                                bo[num0][pp] = true;
                                tail++;
                                tail = tail %qq;
                                for (int i = 0;i <= 5;i++)
                                    dl1[tail][i] = temp[i];
                                dl2[tail] = step + 1;
                                dl3[tail] = pp;
                            }
                    }
            }
    }
    
    int main()
    {
        //freopen("F:\rush.txt","r",stdin);
        input_data();
        get_ans();
        return 0;
    }
    


  • 相关阅读:
    alert
    自定义基类装载数据模块显示到dataGrid
    关于dataGrid查询按钮的实现
    如何查看oracle用户具有的权限和角色 大风起
    LoadRunner使用手册 大风起
    电脑蓝屏了,教你一招保证恢复 大风起
    oracle如何查看当前有哪些用户连接到数据库 大风起
    apache+tomcat整合(动静分离) 大风起
    cdn技术浅谈 大风起
    Tomcat性能优化总结 大风起
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632433.html
Copyright © 2011-2022 走看看