【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);
}

转载于:https://www.cnblogs.com/LinqiongTaoist/p/7203728.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值