BZOJ4111 [Wf2015]Keyboarding——BFS

本文介绍了一种算法,用于计算在给定的虚拟键盘上打印特定文本所需的最少按键次数,包括换行符。该算法利用了BFS搜索策略并进行了优化以减少不必要的节点扩展,确保高效地找到最优解。

escription
给定一个r行c列的在屏幕上的“虚拟键盘”,我们需要通过“上,下,左,右,选择”5个控制键来移动屏幕上的光标来打印文本。一开始,光标在键盘的左上角,每次按方向键,光标总是跳到下一个在该方向上与当前位置不同的字符,若不存在则不移动。每次按选择键,则将光标所在位置的字符打印出来。
现在求打印给定文本(要在结尾打印换行符)的最少按键次数。
Input

第一行输入r,c(1≤r,c≤50)
接下来给出一个r*c的键盘,包括大写字母,数字,横线以及星号(星号代表Enter换行)
最后一行是要打印的文本串s,s的长度不超过10000.
Output

输出打印文本(包括结尾换行符)的最少按键次数。保证一定有解。
Sample Input
2 19

ABCDEFGHIJKLMNOPQZY

X*****************Y

AZAZ

Sample Output
19
HINT

附其余三个样例

Sample Input 1

4 7

ABCDEFG

HIJKLMN

OPQRSTU

VWXYZ**

CONTEST

Sample Output 1

30

Sample Input 2

5 20

12233445566778899000

QQWWEERRTTYYUUIIOOPP

-AASSDDFFGGHHJJKKLL*

–ZZXXCCVVBBNNMM–**


ACM-ICPC-WORLD-FINALS-2015

Sample Output 2

160

Sample Input 3

6 4

AXYB

BBBB

KLMB

OPQB

DEFB

GHI*

AB

Sample Output 3

7


因为某一个点只能往四边走,所以我们预处理出往四边走能走到的地方。
然后我们进行BFS,在BFS时,我么要进行一个优化。由于BFS的性质我们可以知道如果我们某步BFS到的点如果已经被访问过,那么肯定之前访问时走到该点的步数较少。我们记录每一步走的时候,它在我们打印出的字符上的位置,并且如果它访问过一个未访问的节点,那么也给该节点表上当前位置。那么如果一个后入点,它的位置小于先入点的位置,那么它无论如何都不可能更优,所以就不用往下继续拓展了。
而如果后入点的位置更大,那么我们就将当前点的位置赋值为后入点。通过这样的优化就可以很快的跑过了。 //目前速度bzoj第12

#include<bits/stdc++.h>
#define mp make_pair
using namespace std;
int read(){
    char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
    while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;  
}
int n,m,h,t,l,visk[55][55],visp[55][55];
pair<int,int> nxt[55][55][4];
char c[55][55],s[10005];
struct node{
    int x,y,k,pa;
};
queue<node> q;
int main()
{
    n=read();m=read();
    register int i,j,k;
    memset(visk,-1,sizeof(visk));
    for(int i=1;i<=n;i++){
        scanf("%s",c[i]+1);
    }
    scanf("%s",s+1);
    l=1;while(s[l]) l++;s[l]='*';
    for(i=1;i<=n;i++)
     for(j=1;j<=m;j++){
        char s=c[i][j];
        for(k=i+1;k<=n;k++)
         if(c[k][j]!=s){nxt[i][j][0]=mp(k,j);break;}
        for(k=i-1;k;k--)
         if(c[k][j]!=s){nxt[i][j][1]=mp(k,j);break;}
        for(k=j+1;k<=m;k++)
         if(c[i][k]!=s){nxt[i][j][2]=mp(i,k);break;}
        for(k=j-1;k;k--)
         if(c[i][k]!=s){nxt[i][j][3]=mp(i,k);break;}
     }
    q.push((node){1,1,0,0});
    while(!q.empty()){
        node e=q.front();q.pop();
        if(c[e.x][e.y]==s[e.k+1]){
            q.push((node){e.x,e.y,e.k+1,e.pa+1});
            if(e.k+1==l){
                printf("%d\n",e.pa+1);exit(0);
            }
        }
        else for(i=0;i<4;i++){
            pair<int,int> w=nxt[e.x][e.y][i];
            int fi=w.first,se=w.second;
            if(w.first==0) continue;
            if(visk[fi][se]<e.k){
                visk[fi][se]=e.k;
                q.push((node){fi,se,e.k,e.pa+1});
            }
        }
    }
    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值