#10030. 「一本通 1.4 练习 2」Keyboarding

[ICPC2015 WF]Keyboarding

题面翻译

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

题目描述

How many keystrokes are necessary to type a text message? You may think that it is equal to the number of characters in the text, but this is correct only if one keystroke generates one character. With pocket-size devices, the possibilities for typing text are often limited. Some devices provide only a few buttons, significantly fewer than the number of letters in the alphabet. For such devices, several strokes may be needed to type a single character. One mechanism to deal with these limitations is a virtual keyboard displayed on a screen, with a cursor that can be moved from key to key to select characters. Four arrow buttons control the movement of the cursor, and when the cursor is positioned over an appropriate key, pressing the fifth button selects the corresponding character and appends it to the end of the text. To terminate the text, the user must navigate to and select the Enter key. This provides users with an arbitrary set of characters and enables them to type text of any length with only five hardware buttons.

In this problem, you are given a virtual keyboard layout and your task is to determine the minimal number of strokes needed to type a given text, where pressing any of the five hardware buttons constitutes a stroke. The keys are arranged in a rectangular grid, such that each virtual key occupies one or more connected unit squares of the grid. The cursor starts in the upper left corner of the keyboard and moves in the four cardinal directions, in such a way that it always skips to the next unit square in that direction that belongs to a different key. If there is no such unit square, the cursor does not move.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JOTYh3Sf-1687073211325)(https://vj.z180.cn/4393d80e3f068a496c9b906fdca621d9?v=1603457188)]

Figure 1: Sample Input 1. An example virtual keyboard and hardware buttons.

Figure 1, illustrating Sample Input 1, shows a possible way to type CONTEST using 30 strokes on an example virtual keyboard. The red dots represent the virtual keys where the select button was pressed.

输入格式

The first line of the input contains two integers r r r and c c c ( 1 ≤ r , c ≤ 50 1 \leq r, c \leq 50 1r,c50), giving the number of rows and columns of the virtual keyboard grid. The virtual keyboard is specified in the next r r r lines, each of which contains c c c characters. The possible values of these characters are uppercase letters, digits, a dash, and an asterisk (representing Enter). There is only one key corresponding to any given character. Each key is made up of one or more grid squares, which will always form a connected region. The last line of the input contains the text to be typed. This text is a non-empty string of at most 10   000 10\, 000 10000 of the available characters other than the asterisk.

输出格式

Display the minimal number of strokes necessary to type the whole text, including the Enter key at the end. It is guaranteed that the text can be typed.

样例 #1

样例输入 #1

4 7
ABCDEFG
HIJKLMN
OPQRSTU
VWXYZ**
CONTEST

样例输出 #1

30

样例 #2

样例输入 #2

5 20
12233445566778899000
QQWWEERRTTYYUUIIOOPP
-AASSDDFFGGHHJJKKLL*
--ZZXXCCVVBBNNMM--**
--------------------
ACM-ICPC-WORLD-FINALS-2015

样例输出 #2

160

样例 #3

样例输入 #3

2 19
ABCDEFGHIJKLMNOPQZY
X*****************Y
AZAZ

样例输出 #3

19

样例 #4

样例输入 #4

6 4
AXYB
BBBB
KLMB
OPQB
DEFB
GHI*
AB

样例输出 #4

7

提示

Time limit: 3000 ms, Memory limit: 1048576 kB.

International Collegiate Programming Contest (ACM-ICPC) World Finals 2015

大致思路

  • 数据范围不大,暴力BFS即可
  • BFS队列中的元素记录当前位置和当前匹配的位数
  • 但是要求下一个字符与当前位置不同,可能会有大量无用计算
  • 需要预处理出每个位置在每个方向上下一个位置
void init(){//预处理
		sy[0]=sy[2]=y,sx[1]=sx[3]=x;
		for(int i=x;i&&mi[i][y]==a;i--) sx[0]=i;sx[0]--;
		for(int i=x;i<=n&&mi[i][y]==a;i++) sx[2]=i;sx[2]++;
		for(int j=y;j<=m&&mi[x][j]==a;j++) sy[1]=j;sy[1]++;
		for(int j=y;j&&mi[x][j]==a;j--) sy[3]=j;sy[3]--;
	}

剩下的依旧是bfs模板

void bfs(){
	queue<node> q;
	q.push(node(1, 1, 0, 0));
	while(!q.empty()){//逐个匹配
		node k=q.front();
		q.pop();
		if(mp[k.a][k.b].a==s[k.t]){
			if(k.t==len){
				printf("%d\n",k.step+1);
				return;
			}
			vis[k.a][k.b] =k.t+1;
			q.push(node(k.a,k.b,k.t+1,k.step+1));
			continue;
		}
		for(int i=0;i<4;i++) {
			int dx=mp[k.a][k.b].sx[i],dy=mp[k.a][k.b].sy[i];
			if(dx<1||dx>n||dy<1||dy>m) continue;
			if(dx==k.a&&dy==k.b) continue;
			if(vis[dx][dy]>=k.t) continue;
			vis[dx][dy]=k.t;
			q.push(node(dx,dy,k.t,k.step+1));
		}
	}
}
  • AC CODE

#include<bits/stdc++.h>
using namespace std;
int n,m,ans,len,vis[55][55],mi[55][55];
char s[10005];
struct point{
	int a,x,y,sx[4],sy[4];
	void init(){//预处理
		sy[0]=sy[2]=y,sx[1]=sx[3]=x;
		for(int i=x;i&&mi[i][y]==a;i--) sx[0]=i;sx[0]--;
		for(int i=x;i<=n&&mi[i][y]==a;i++) sx[2]=i;sx[2]++;
		for(int j=y;j<=m&&mi[x][j]==a;j++) sy[1]=j;sy[1]++;
		for(int j=y;j&&mi[x][j]==a;j--) sy[3]=j;sy[3]--;
	}
}mp[55][55];
struct node{
	int a, b, t, step;
	node(int aa,int bb,int tt,int ss){
		a=aa,b=bb,t=tt,step=ss;
	}
};
void bfs(){
	queue<node> q;
	q.push(node(1, 1, 0, 0));
	while(!q.empty()){//逐个匹配
		node k=q.front();
		q.pop();
		if(mp[k.a][k.b].a==s[k.t]){
			if(k.t==len){
				printf("%d\n",k.step+1);
				return;
			}
			vis[k.a][k.b] =k.t+1;
			q.push(node(k.a,k.b,k.t+1,k.step+1));
			continue;
		}
		for(int i=0;i<4;i++) {
			int dx=mp[k.a][k.b].sx[i],dy=mp[k.a][k.b].sy[i];
			if(dx<1||dx>n||dy<1||dy>m) continue;
			if(dx==k.a&&dy==k.b) continue;
			if(vis[dx][dy]>=k.t) continue;
			vis[dx][dy]=k.t;
			q.push(node(dx,dy,k.t,k.step+1));
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		for(int j=1;j<=m;j++){
			mi[i][j]=mp[i][j].a=s[j];
			mp[i][j].x=i,mp[i][j].y=j;
			vis[i][j]=-1;
		}
	}
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++) mp[i][j].init();
	scanf("%s", s);
	len=strlen(s);
	s[len]='*';
	bfs();
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值