题意:给定一个r*c的键盘,键盘由字母和数字还有一些符号的按键组成,键盘光标的起始位置在左上角,每次移动可以朝上下左右四个方向跳到一个和当前位置字符不同的按键处,给定一串长字符,问至少要按多少次键盘。
分析:直接BFS,f[i][j][k]表示当前在(i,j)位置,已经按了k个键的最小值。
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
struct point
{
int x,y;
point() {}
point(int a,int b)
{
x = a;
y = b;
}
}up[51][51],Right[51][51],down[51][51],Left[51][51];
int n,r,c,num,ans,jud[51][51][10005],f[51][51][10005],q[51*51*10000][3];
vector<point> F[150];
char s[52][52],S[10005];
int main()
{
while(~scanf("%d%d",&r,&c))
{
++num;
memset(up,-1,sizeof(up));
memset(Right,-1,sizeof(Right));
memset(Left,-1,sizeof(Left));
memset(down,-1,sizeof(down));
for(int i = 0;i <= 150;i++) F[i].clear();
for(int i = 1;i <= r;i++) scanf("%s",s[i]);
for(int i = 1;i <= r;i++)
for(int j = 0;j < c;j++)
F[s[i][j]].push_back(point(i,j));
for(int i = 1;i <= r;i++)
for(int j = 0;j < c;j++)
{
if(s[i][j] == s[i-1][j]) up[i][j] = up[i-1][j];
else
{
if(i != 1)
{
up[i][j].x = i-1;
up[i][j].y = j;
}
}
if(j && s[i][j] == s[i][j-1]) Left[i][j] = Left[i][j-1];
else
{
if(j)
{
Left[i][j].x = i;
Left[i][j].y = j-1;
}
}
}
for(int i = r;i;i--)
for(int j = c-1;j >= 0;j--)
{
if(i != r && s[i][j] == s[i+1][j]) down[i][j] = down[i+1][j];
else
{
if(i != r)
{
down[i][j].x = i+1;
down[i][j].y = j;
}
}
if(j != c-1 && s[i][j] == s[i][j+1]) Right[i][j] = Right[i][j+1];
else
{
if(j != c-1)
{
Right[i][j].x = i;
Right[i][j].y = j+1;
}
}
}
scanf("%s",S);
n = strlen(S);
S[n++] = '*';
int l = 1,r = 2;
q[1][0] = 1,q[1][1] = 0,q[1][2] = 0;
jud[1][0][0] = num;
while(l != r)
{
int x = q[l][0],y = q[l][1],k = q[l][2];
l++;
if(s[x][y] == S[k])
{
int nx = x,ny = y,nk = k+1;
if(jud[nx][ny][nk] != num)
{
q[r][0] = nx,q[r][1] = ny,q[r][2] = nk;
f[nx][ny][nk] = 1 + f[x][y][k];
jud[nx][ny][nk] = num;
r++;
}
}
if(up[x][y].x >= 0)
{
int nx = up[x][y].x,ny = up[x][y].y,nk = k;
if(jud[nx][ny][nk] != num)
{
q[r][0] = nx,q[r][1] = ny,q[r][2] = nk;
f[nx][ny][nk] = 1 + f[x][y][k];
jud[nx][ny][nk] = num;
r++;
}
}
if(down[x][y].x >= 0)
{
int nx = down[x][y].x,ny = down[x][y].y,nk = k;
if(jud[nx][ny][nk] != num)
{
q[r][0] = nx,q[r][1] = ny,q[r][2] = nk;
f[nx][ny][nk] = 1 + f[x][y][k];
jud[nx][ny][nk] = num;
r++;
}
}
if(Left[x][y].x >= 0)
{
int nx = Left[x][y].x,ny = Left[x][y].y,nk = k;
if(jud[nx][ny][nk] != num)
{
q[r][0] = nx,q[r][1] = ny,q[r][2] = nk;
f[nx][ny][nk] = 1 + f[x][y][k];
jud[nx][ny][nk] = num;
r++;
}
}
if(Right[x][y].x >= 0)
{
int nx = Right[x][y].x,ny = Right[x][y].y,nk = k;
if(jud[nx][ny][nk] != num)
{
q[r][0] = nx,q[r][1] = ny,q[r][2] = nk;
f[nx][ny][nk] = 1 + f[x][y][k];
jud[nx][ny][nk] = num;
r++;
}
}
}
ans = INF;
for(point v : F['*'])
if(jud[v.x][v.y][n] == num)
ans = min(ans,f[v.x][v.y][n]);
cout<<ans<<endl;
}
}