题解 P6909 【[ICPC2015 WF]Keyboarding】
坑点提醒
1、最后需要你手动添加一个
2、注意在其实位置按键的情况
思路
首先我们可以把所有相关涉及到的字符都映射为数字,方便处理,包括
当我们输入的时候直接映射到一个二维数组
将目标串映射到一个一维数组
那么如何选择位置呢,如果在搜索的过程中暴力美剧会非常耗时间,那么这个时候就可以预处理每一个键第一个到达的位置即可
为了方便我们要设一个结构体类型的三维数组
结构体的变量分别为 到达的位置的横坐标
三维数组
那么预处理之后就开始广搜了
在开始广搜之前,因为我们是从第一位开始的,那么我们最好先预处理一下在第一位一共可以连续按几次,然后再把结构体重所表示的数据存进去,在代码中有就不详细说了
那么现在开始广搜
考虑两种情况,我们要把选择和匹配分开找
一、
那么先是匹配,要看一下堆顶的这个位置是否和当前要匹配的位置相同,如果是相同的时候,那就在进行判断一下这个是不是最终状态,如果是,那直接把答案赋值为当前的步数+1就是最有的答案
那如果不是最后的一个情况呢
可以设一个
二、
最后再开始选择
首先枚举该点四个位置的到达点,当然因为我在预处理位置的时候有一个位置得移动忘加了,所以还要加上,一次移动
首先判断一下是否越界
然后再判断一下当前要选择的地方要比原坐标的要处理的位置要更大,那么就不需要更新
否则的话,就更新当前的
最后直接输出即可
代码实现
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
using namespace std;
const int N=59;
const int M=10009;
struct node{
int x;
int y;
int step;//指下一个到了第几个位置,
int dis;//按了几次
}f[5][N][N];//后两个表示坐标,前一个表示方向,即i,j在k方向上到的最近的点
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
char wor[M];
int n,m,len,a[N][N],b[M],vis[N][N];
map<char,int> mp;
void prepare()//预先将所有的字符串处理成数字类型的,方便处理
{
for(int i=0;i<=9;i++)
mp[(char)('0'+i)]=i+1;
for(int i=0;i<26;i++)
mp[(char)('A'+i)]=i+11;//1-10被取过了
mp['-']=37;
mp['*']=38;
}
void get()//处理一下四个方向可以到达的点
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
{
int x=i;
int y=j;
while(a[x][y]==a[x+dx[k]][y+dy[k]])//如果一致的话
{
x+=dx[k];
y+=dy[k];//一致加到不同为止
}
f[k][i][j]=(node){x,y,0,0};
}
}
int search()
{
memset(vis,0,sizeof(vis));
queue<node> q;
int ans=0;
int k=1;
while(a[1][1]==b[k]&&k<=len) ++k;//在起点选取的情况
q.push((node){1,1,k,k-1});
vis[1][1]=k;
while(!q.empty())
{
node cun=q.front();
q.pop();
int x=cun.x;
int y=cun.y;
int now=cun.step;
if(a[x][y]==b[now])//此时相等了
{
if(now==len)
{
ans=cun.dis+1;
break;//如果找完了?直接跳出
}
vis[x][y]=now+1;//更新一下,因为按了一遍键盘
q.push((node){x,y,now+1,cun.dis+1});
}
for(int i=0;i<4;i++)
{
node chose=f[i][x][y];
chose.x+=dx[i];
chose.y+=dy[i];//预处理上在加一次,保证完整
if(chose.x<1||chose.x>n||chose.y<1||chose.y>m) continue;//越界了
if(vis[chose.x][chose.y]>=now) continue;//如果选择的地方的要处理的位置比现在的要大,不用改,防止变worse
vis[chose.x][chose.y]=now;//如果可行,那么把接下来要弄得位置给存进去
q.push((node){chose.x,chose.y,now,cun.dis+1});//跳到那一步
}
}
return ans;
}
int main()
{
prepare();
while(scanf("%d",&n)!=EOF)//UVA经典输入方式
{
// cin>>n;
cin>>m;
for(int i=1;i<=n;i++)//输入每一行的字符串
{
cin>>wor;
for(int j=0;j<m;j++)
a[i][j+1]=mp[wor[j]];//将每个字符的代表的数字映射到a数组中
//从1开始方便
}
cin>>wor;
len=strlen(wor);
for(int i=0;i<len;i++) b[i+1]=mp[wor[i]];//依旧是映射,从1开始
len++;
b[len]=38;//注意最后有一个*
get();
cout<<search()<<endl;
}
return 0;
}