【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\n",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\n",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\n",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\n",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;
}
时间: 2024-10-10 07:17:09

【8001】输入密码的相关文章

已经在Git Server服务器上导入了SSH公钥,可用TortoiseGit同步代码时,还是提示输入密码?

GitHub虽好,但毕竟在国内访问不是很稳定,速度也不快,而且推送到上面的源码等资料必须公开,除非你给他交了保护费:所以有条件的话,建议大家搭建自己的Git Server.本地和局域网服务器都好,不信你试试,那速度,怎一个爽字了得! 默认情况下,使用TortoiseGit同步代码,每次都需要输入用户名和密码,但为了方便可以在客户端创建ssh密钥,用于服务器端和客户端的认证(详细过程大家可参考这里),但有时会出现“ 已经在Git Server服务器上导入了SSH公钥,可用TortoiseGit同步

解决eclipse中svn插件总是提示输入密码的问题

一.背景 最近在eclipse中使用svn插件进行远程仓库代码管理时,老是出现提示让输入密码,特别烦人,经过努力,终于解决该问题,拿来和大家分享~ 二.svn插件密码机制以及出现问题的原因分析 当我们第一次使用svn插件并输入密码时,会生成一个保存密码的文件,然后每次svn插件默认去读取用户名和密码信息.启动eclipse时,会自动将配置信息读取到程序缓存中. svn的密码修改以后,无法再次登录,也没有提示重新输入密码.这时,我们可以通过删除相关配置文件的方式让svn插件提示我们重新输入密码.但

python-getpass模块 实现&#8203;输入密码时候不显示

import getpass username = input("username:") password = getpass.getpass("password:") print(username,password) 实现输入密码时候不显示 windows_python不生效,linux环境测试成功.

如何实现色条随输入密码长度变化效果

如何实现色条随输入密码长度变化效果:在很多网站注册页面都有这样的功能,当用户输入密码的时候,下面会出现一个色条,色条的长度会跟随输入密码的长度变化,并且色条的颜色也会根据输入密码长度的不同有所改变,一般是用来提示密码强度.下面就简单介绍一下使用jQuery如何实现此功能.代码实例如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="auth

微信支付:H5吊起支付API,不显示&ldquo;确认支付、输入密码&rdquo;界面

使用公众号进行支付,官方开发帮助文档: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1 其业务流程如下: 按照业务流程进行开发,依据官方的例子,不能弹出选择支付方式及输入密码,页面js代码如下: //调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', <%=wxJsApiParam%>,//josn串 fu

使用sudo而无需输入密码的设置

在linux上,root用户是老大,什么事都能做.但是,很多时候由于安全等各种原因,我们不希望把root用户开放给大家,但是又希望其他的用户可以有root的权限,所以就有了sudo用户.而执行sudo命令的时候,又总会要让你输用户密码,也是很头痛的事情,接下来将演示如何创建sudo用户,并且在用sudo的时候不需要密码. 1.进入超级用户模式.也就是输入"su -",系统会让你输入超级用户密码,输入密码之后就进入了超级用户模式.(当然,也可以直接用root登陆) 2.编辑/etc/su

解决ssh配置无密码登陆后再次出现请求输入密码的情况

http://inuyasha1027.blog.51cto.com/4003695/1132896/ 主机ip:192.168.163.100(hostname: node0) ssh无密码登陆的远程机ip:192.168.163.101(hostname: node1) 首先要修改主机 和ssh连接到的远程机 的配置文件: vi  /etc/ssh/sshd_config (要确保这些字符前无注释符号"#") RSAAuthentication  yes PubkeyAuthent

连不上无线网-只有自己的wifi连不上,不显示输入密码对话框的解决办法

这里顺便提一下,若是右下角显示红叉,可以Fn+F7(你的电脑是哪个组合键,你看看按键上面的图案就知道),若不是红叉问题,一切正常,搜索到很多wifi就是连不上自己的,问题原因就是上次连接后生成的东西没有删除干净,在 控制面板\网络和 Internet\网络和共享中心 中 点击管理无线网络,进入后删除原来保存的信息,你肯定认识,那就是你之前连上的wifi相关信息.右击它,删除 ,再次尝试连接你的无线网,你会发现,迅速出现输入密码框,ok,问题解决

[转]Ubuntu默认使用root用户登录并免去输入密码

启用Root用户登录 Ctrl + Alt + T进入终端, 输入cd /usr/share/lightm/ightm.conf.d, 如果提示你没有那个文件或目录.那就一次次的进入目录. 进入之后会看到如图所示的几个文件. 这里写图片描述 输入命令vi 50-unity-greeter.conf添加: greeter-show-manual-login=true allow-guest=false  这时候重启就可以使用Root用户登陆了, 输入用户名root以及root用户的密码敲Enter