P6909 [ICPC2015 WF] Keyboarding 题解
我不理解,为什么这道题没有多组测试但是一大堆题解写了多测。
一道有坑的题。结尾要打印空格,即 *。而且最后搜到空格还要再按键。
解法
看到数据范围 n,m≤50n,m \le 50n,m≤50,于是考虑广度优先搜索。
因为光标总是跳到下一个在一方向上与当前位置不同的字符,所以我们考虑 O(n3)\mathcal{O}(n^3)O(n3) 预处理出每个位置上下左右能跳到哪里,方便下面的搜索。
搜索中我们记录搜到的位置、已经打印出的字符数量和按键次数。
对于每次搜索,如果现在搜到的位置可以打印出字符,那么我们就将其打印出来,再向 444 个方向搜索下面的字符。注意到我们用的是广度优先搜索,所以第一次打印完所有字符一定是最优解。
剪枝
-
考虑如果一个位置的一个方向上没有与这个位置不同的字符,那我们就不去搜索这个方向,可以通过预处理完成。
-
考虑到搜索时有可能出现从一个点开始向左搜索但是没有搜到答案又向右搜回这个点的情况,我们就标记搜到一个位置最多可以打印出的字符,记作 visi,jvis_{i,j}visi,j,如果搜到一个点现在打印出的字符比 visi,jvis_{i,j}visi,j 小,则剪枝。
代码
#include<bits/stdc++.h>
using namespace std;
namespace fast_IO
{
/*
快读快写,这里不贴了。忽略即可。
*/
};
using namespace fast_IO;
int n,m,dx[100][100][5],dy[100][100][5],vis[100][100];
char a[100][100];
string st;
inline void init()
{
for(int x=1;x<=n;x++)
for(int y=1;y<=m;y++)
{
dx[x][y][2]=dx[x][y][4]=x,dy[x][y][1]=dy[x][y][3]=y;
for(int i=x;i && a[x][y]==a[i][y];i--) dx[x][y][1]=i;
for(int i=x;i<=n && a[x][y]==a[i][y];i++) dx[x][y][3]=i;
for(int i=y;i<=m && a[x][y]==a[x][i];i++) dy[x][y][2]=i;
for(int i=y;i && a[x][y]==a[x][i];i--) dy[x][y][4]=i;
dx[x][y][1]--,dy[x][y][2]++,dx[x][y][3]++,dy[x][y][4]--;
}
}
struct node
{
int x,y,pos,cost;
};
node tmp;
deque<node> q;
inline bool inrange(const int &x,const int &y,const int &i)
{
return (dx[x][y][i]>=1 && dx[x][y][i]<=n && dy[x][y][i]>=1 && dy[x][y][i]<=m);
}
int main()
{
read(n),read(m),memset(vis,-1,sizeof(vis));
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(a[i][j]);
read(st),st=st+"*",init(),q.clear(),q.push_back((node){1,1,0,0});
while(!q.empty())
{
tmp=q.front(),q.pop_front();
if(a[tmp.x][tmp.y]==st[tmp.pos])
{
if(tmp.pos==st.size()-1)
{
cout<<tmp.cost+1<<"\n";
return 0;
}
vis[tmp.x][tmp.y]=tmp.pos+1,q.push_back((node){tmp.x,tmp.y,tmp.pos+1,tmp.cost+1});
}else
{
for(int i=1;i<=4;i++)
if(inrange(tmp.x,tmp.y,i) && vis[dx[tmp.x][tmp.y][i]][dy[tmp.x][tmp.y][i]]<tmp.pos)
vis[dx[tmp.x][tmp.y][i]][dy[tmp.x][tmp.y][i]]=tmp.pos,
q.push_back((node){dx[tmp.x][tmp.y][i],dy[tmp.x][tmp.y][i],tmp.pos,tmp.cost+1});
}
}
return 0;
}
本文介绍了如何解决ICPC2015WF竞赛中的Keyboarding问题,使用广度优先搜索策略规划字符跳动路径,通过剪枝优化算法减少不必要的搜索,最终实现按最少按键次数打印字符并以空格结束。

被折叠的 条评论
为什么被折叠?



