1184 聪明的打字员

聪明的打字员
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 3409 Accepted: 705

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
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int _max=1000001;
int pre,end;//初始状态和目标状态,用整形保存
int fin[6];//目标状态,用数组保存
bool vis[_max][10];//最多有不超过_max个节点,光标最多有10种状态
struct  Node
{
    int state;//当前状态,用整形保存
    int step;//当前步骤
    int visited;//0-9
/*
0:0      通过right操作或者是swap0操作,但是光标停留在最后一个元素,没有执行swap1操作
1:0, 1
2:0, 1, 2
3:0, 1, 2, 3
4:0, 1, 2, 3, 4
5:0, 5  通过swap1操作,但是光标还是停留在i-5处
6:0, 1, 5
7:0, 1, 2, 5
8:0, 1, 2, 3, 5
9:0, 1, 2, 3, 4, 5
*/
// 不需要考虑left操作,因为没有意义
};
int abss(int x) {return x>0?x:-x;}
void toarray(int n,int *a)//将整数保存到数组中
{
    for(int i=5;i>=0;i--)
    {
        a[i]=n%10;
        n/=10;
    }
}
int tonum(int *a)//将数组转化成整数形式
{
    int cnt=0;
    for(int i=0;i<6;i++) cnt=cnt*10+a[i];
    return cnt;
}
int swapnum(int n,int m,int *a)//返回a[n]和a[m]交换后的状态,但是并不真的交换
{
    swap(a[n],a[m]);
    int cnt=tonum(a);
    swap(a[n],a[m]);//复位
    return cnt;
}
int check(const Node& temp)//检查当前状态是否和目标状态相同(这里只比较光标尚未走过的区域),返回-1表示不相同
{
    int a[6];
    toarray(temp.state,a);//将此时状态保存到a数组中,便于和目标状态比较
    int tmp=temp.visited;//当天光标遍历过的位置
    int cnt=0;//保存和目标状态相差的步数(只用up和down操作)
    if(tmp<=4) //尚未执行swap1操作,光标只是右移或者是执行swap0操作
    {
        for(int i=tmp+1;i<6;i++)// 需要比较到最后一个
        {
            if(a[i]!=fin[i]) return -1;//和目标状态不同
        }
        for(int i=0;i<=tmp;i++) cnt+=abss(a[i]-fin[i]);//通过up和down操作
    }
    else //已经执行过了swap1操作,但是光标还是停留在tmp-5处
    {
        tmp-=5;//当天光标位置
        for(int i=tmp+1;i<5;i++)// 只需比较到第5个
        {
            if(a[i]!=fin[i]) return -1;//和目标状态不同
        }
        for(int i=0;i<=tmp;i++) cnt+=abss(a[i]-fin[i]);//通过up和down操作
        cnt+=abss(a[5]-fin[5]);
    }
    return cnt;
}
queue<Node> q;
int bfs()
{
    while(!q.empty()) q.pop();
    memset(vis,0,sizeof(vis));
    int _min=_max;//最小步数
    Node st;
    st.state=pre,st.step=0,st.visited=0;//初始化
    vis[pre][0]=1;
    q.push(st);
    while(!q.empty())
    {
        Node p=q.front();q.pop();
        int ori=p.state,visited=p.visited;//保存数据,防止下面操作将其值覆盖
        int res=check(p);//表示和目标状态还差多少步,-1表示和目标状态不相同
        if(res!=-1)
        {
            if(p.step+res<_min) _min=p.step+res;//到目标状态总的步数
        }
        //拓展节点
        p.step++;//步数加1,important 不能在下面加,否则会重复加
        if(p.step>=_min) continue;//剪枝
        int a[6];
        toarray(p.state,a);//保存当前状态
        int tmp;//保存执行swap 0后的状态,用整形保存
        //swap 0
        if(p.visited>0) //如果在0点的话,不用执行swap 0
        {
            if(p.visited>=5) //已经执行过了swap 1
            {
                tmp=swapnum(0,p.visited-5,a);
            }
            else
            {
                tmp=swapnum(0,p.visited,a);
            }
            if(!vis[tmp][p.visited])//如果当前状态尚未走过
            {
                p.state=tmp;
                q.push(p);
                vis[tmp][p.visited]=1;
            }
        }
        //swap 1
        if(p.visited<5) //尚未执行swap 1操作
        {
            tmp=swapnum(5,p.visited,a);
            p.visited+=5;//important
        }
        else
        {
            tmp=swapnum(5,p.visited-5,a);
        }
        if(!vis[tmp][p.visited])
        {
            p.state=tmp;
            //p.visited不用改变
            q.push(p);
            vis[tmp][p.visited]=1;
        }
        //right
        p.state=ori,p.visited=visited;//恢复数据
        if(p.visited<5)
        {
            p.visited++;
            if(!vis[p.state][p.visited]) q.push(p);
        }
        else if(p.visited<9)
        {
            p.visited++;
            if(!vis[p.state][p.visited]) q.push(p);
        }
    }
    return _min;
}
/*int bfs( )
{
    queue<Node> q;
    Node p;
    int ori, visited, tmp, a[ 6 ] , res, _min = _max;
    memset ( vis, false , sizeof ( vis) ) ;
    p.state = pre;
    p.step = 0 ;
    p.visited = 0 ;
    q.push ( p) ;
    vis[ pre] [ 0 ] = true ;
    while ( !q.empty ( ) )
    {
        p = q.front ( ) ;
        q.pop ( ) ;
        ori = p.state ;
        visited = p.visited ;
        res = check( p) ;
        if ( res != -1 )
        {
            if ( _min > res + p.step ) _min= p.step + res;
        }
        p.step ++;
        if ( p.step >= _min) continue ;//剪枝
        toarray( p.state , a) ;
        //swap0
        if ( p.visited > 0 )
        {
            if ( p.visited >= 5 ) tmp = swapnum( 0 , p.visited - 5 , a) ;
            else tmp = swapnum( 0 , p.visited , a) ;
            if ( !vis[ tmp] [ p.visited ] )
            {
                p.state = tmp;
                q.push ( p) ;
                vis[ tmp] [ p.visited ] = true ;
            }
        }
        //swap1
        if ( p.visited < 5 )
        {
            tmp = swapnum( 5 , p.visited , a) ;
            p.visited += 5 ;
        }
        else tmp = swapnum( 5 , p.visited - 5 , a) ;
        if ( !vis[ tmp] [ p.visited ] )
        {
            p.state = tmp;
            q.push ( p) ;
            vis[ tmp] [ p.visited ] = true ;
        }
        //right
        p.state = ori;
        p.visited = visited;
        if ( p.visited < 5 )
        {
            p.visited ++;
            if ( !vis[ p.state ] [ p.visited ] ) q.push ( p) ;
        }
        else if ( p.visited < 9 )
        {
            p.visited ++;
            if ( !vis[ p.state ] [ p.visited ] ) q.push ( p) ;
        }
    }
    return _min;
}*/
int main()
{
    while(scanf("%d%d",&pre,&end)==2)
    {
        toarray(end,fin);
        int cnt=bfs();
        printf("%d/n",cnt);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值