Keyboarding

https://loj.ac/problem/10030

题目描述

  给出一个虚拟键盘,键盘上有一光标,可以上下左右移动,移动时沿该方向一直移动到不同字符,求将给定字符串输出的最小步数(初始位置在左上角,移动为一步,点击键盘为一步,字符串结尾有换行符,用(‘*’)表示)。

思路

  首先每一步移动时都可能会移动多步,而数据范围又比较小,所以我们可以先预处理出从((i,j))位置出发沿四个方向所移动的步数。接下来就开始(bfs)。不过这道题的特殊之处是我们需要存储两个量,表示到((i,j))这个位置经过(step)步最多能输出多少个给定的字符。这样我们就可以用一个数组来存到((i,j))最多完成几个字符的输出,就可以减少不必要的求解。而对于目前所在的位置就是要输出的字符特殊处理一下即可。

代码

#include <bits/stdc++.h>
using namespace std;
struct aa
{
    int x,y,step,num;
    aa(int x=0,int y=0,int step=0,int num=0):x(x),y(y),step(step),num(num){}
};
int dx[5]={1,-1,0,0},dy[5]={0,0,1,-1};
int v[60][60],a[60][60][5];
char goal[10100],key[60][60];
queue<aa> q;
int main() 
{
    int len,ans,r,c;
    scanf("%d%d",&r,&c);
    for(int i=1;i<=r;i++)
        scanf(" %s",key[i]+1);
    scanf(" %s",goal+1);
    goal[strlen(goal+1)+1]='*';
    len=strlen(goal+1);
    for(int i=1;i<=r;i++)
        for(int j=1;j<=c;j++)
            for(int k=0;k<4;k++)
            {
                int nx=i,ny=j,t=0;
                while(nx>0&&nx<=r&&ny>0&&ny<=c)
                {
                    if(key[nx][ny]!=key[i][j])break ;
                    nx+=dx[k];ny+=dy[k];t++;
                }
                if(nx>0&&nx<=r&&ny>0&&ny<=c)
                    a[i][j][k]=t;                //从(i,j)沿k方向要走多少步 
            }
    v[1][1]=1;                                    //到(i,j)最多输出多少字符 
    q.push(aa(1,1,0,1));
    while(!q.empty())
    {
        aa nex,now=q.front();q.pop();
//        cout<<now.x<<' '<<now.y<<' '<<goal[now.num]<<endl;
        if(key[now.x][now.y]==goal[now.num]&&v[now.x][now.y]<now.num+1)
        {
//            cout<<now.x<<' '<<now.y<<' '<<goal[now.num]<<endl;
            v[now.x][now.y]=now.num+1;
            nex=aa(now.x,now.y,now.step+1,now.num+1);
            if(nex.num>len){ans=nex.step;break ;}
            q.push(nex);
        }
        else
        {
            for(int i=0;i<4;i++)
            {
                int bias=a[now.x][now.y][i];
                if(bias)
                {
                    nex=aa(now.x+bias*dx[i],now.y+bias*dy[i],now.step+1,now.num);
//                    cout<<nex.x<<' '<<nex.y<<' '<<goal[nex.num]<<endl;
                    if(nex.num<=v[nex.x][nex.y])continue ;
                    v[nex.x][nex.y]=nex.num;
                    q.push(nex);
                }
            }
        }
    }
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/fangbozhen/p/11766845.html