Keyboarding (bfs+预处理+判重优化)

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

【题目描述】

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

【算法】

1、预处理四个方向能到达的点。
2、$bfs$ 判重记录状态:
v[i][j]数组记录在(i,j)位置已打印的字符个数,判重:若当前位于(i,j)点将要处理第n个字符则能进入队列的条件是n>v[i][j]
3、1个小优化:
若当前状态和待处理字符匹配,则不打印而继续向四个方向延申的操作肯定非最优

【代码】

#include <bits/stdc++.h>
using namespace std;
struct state{ int x,y,num,step; }st;
int r,c,all,ans;
int a[55][55][4],v[55][55];
char s[55][55],res[10100];
queue<state> q;
const int dx[4]={ -1,0,1,0 },dy[4]={ 0,1,0,-1 };
void parse() {
    for(int i=1;i<=r;i++) {
        for(int j=1;j<=c;j++) {
            for(int k=0;k<4;k++) {
                int nx=i,ny=j,t=0;
                while(nx>=1&&nx<=r&&ny>=1&&ny<=c) {
                    if(s[nx][ny]!=s[i][j]) break;
                    nx+=dx[k],ny+=dy[k],t++;
                }
                if(nx>=1&&nx<=r&&ny>=1&&ny<=c) a[i][j][k]=t;
            }
        }
    }
}
void bfs() {
    v[1][1]=1;
    q.push((state){ 1,1,1,0 });
    while(q.size()) {
        state next,now=q.front(); q.pop();
        if(s[now.x][now.y]==res[now.num]&&v[now.x][now.y]<now.num+1) {
            v[now.x][now.y]=now.num+1;
            next=(state){ now.x,now.y,now.num+1,now.step+1 };
            if(next.num>all) { ans=next.step; break; }
            q.push(next);
        }
        else for(int i=0;i<4;i++) {
            int bias=a[now.x][now.y][i];
            if(bias) {
                next=(state){ now.x+bias*dx[i],now.y+bias*dy[i],now.num,now.step+1 };
                if(v[next.x][next.y]>=next.num) continue;
                v[next.x][next.y]=next.num;
                q.push(next);
            }
        }
    }
}
int main() {
    scanf("%d%d",&r,&c);
    for(int i=1;i<=r;i++) scanf("%s",s[i]+1);
    scanf("%s",res+1); res[strlen(res+1)+1]='*';
    all=strlen(res+1);
    parse();
    bfs();
    printf("%d\n",ans);
    return 0;
}

【其它】 ahhhh,wf的题目~开心

原文地址:https://www.cnblogs.com/Willendless/p/9591481.html

时间: 2024-10-16 00:43:11

Keyboarding (bfs+预处理+判重优化)的相关文章

HDU 4474&amp;&amp;POJ 1465 BFS&amp;&amp;余数判重

两道题只是输入输出格式略有不同 给出n,m,m个数 要求生成一个数x,是n的倍数,并且只由这M个数构成(或不能含有这M个数中的任意一个),求最小的x,没有则输出-1(0): BFS找每一个满足n的倍数的数,用余数判重优化 对于给定两个数A,B,如果A和B模N都相同,设为C,即: A=x*N+C B=y*N+C 那么如果在A后面加上一个数字能够被N整除,则在B后面加上这个数字也肯定可以被N整除 即:(A*10+X)%N==(B*10+X)%N 因此可以利用模N的结果进行判重,只保留相同余数的最小数

11198 - Dancing Digits(BFS + hash判重)

题目:11198 - Dancing Digits 题目大意:每组数据给出8个数字,可能正可能负.要求最后将这8个数字按照数字绝对值从小到大的排序.排序的规则是让某个数字a邀请另一个数字b跳舞,这样a就可以插到b的左边或是右边,a能邀请b跳舞,则a* b <0 ,且a+b要是素数.题目问给出一组数据问能否通过邀请跳舞来排序,能的话就输出最少的邀请次数,否则输出-1. 解题思路:这题一开始竟然想着dfs,但是后面发现,这样的判断树可以是无限大,因为可以a邀请完b,然后b在邀请a,这样一来一回有可能

poj1465Multiple(经典BFS+余数判重)

Multiple Time Limit: 1000MS   Memory Limit: 32768K Total Submissions: 6936   Accepted: 1495 Description a program that, given a natural number N between 0 and 4999 (inclusively), and M distinct decimal digits X1,X2..XM (at least one), finds the small

[bfs+余数判重+路径记录] hdu 4474 Yet Another Multiple Problem

题意: 给一个n和m个数字(一位数) 求最小的n的倍数不含有这m个数字,不存在输出-1 思路: 首先有可能这个数超long long 所以无法暴力解决 所以这题应该是一个bfs 为什么能用余数判重呢 对于当前的余数进到队列里,一定是这个余数对应数的最小值 接下来再怎么添加到满足条件的后续东西应该是一样的 所以就可以余数判重了,类似数位dp的记录方式 然后再加上一个路径记录就好了 代码: #include"cstdlib" #include"cstdio" #incl

HDU 2579 Dating with girls(2) BFS 余数判重

对于石头的处理就按照每个位置的时间取k的余数判一下重复就好,其他随意写 #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector> #include <string> #include <queue> #include <deque> #include

BFS+Hash(储存,判重) HDOJ 1067 Gap

题目传送门 题意:一个图按照变成指定的图,问最少操作步数 分析:状态转移简单,主要是在图的存储以及判重问题,原来队列里装二维数组内存也可以,判重用神奇的hash技术 #include <bits/stdc++.h> using namespace std; const int MOD = 1e6 + 7; struct Point { int ch[5][9]; int x[4], y[4]; int step; }; bool vis[MOD]; int ha; int get_hash(i

八数码问题+路径寻找问题+bfs(隐式图的判重操作)

Δ路径寻找问题可以归结为隐式图的遍历,它的任务是找到一条凑够初始状态到终止问题的最优路径, 而不是像回溯法那样找到一个符合某些要求的解. 八数码问题就是路径查找问题背景下的经典训练题目. 程序框架 process()  初始化vis数组,初始化初始节点到目标节点的移动距离 dfs()搜索到每一个节点,如果不是目标节点,对其依次扩展所有子节点,并判重,全部子节点搜索完全后,改变父节点:如果是目标节点成功返回 输出最少移动步数 input: 2 6 4 1 3 7 0 5 8 8 1 5 7 3 6

hdu 1226 超级密码 bfs+取余判重

超级密码 Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2808    Accepted Submission(s): 897 Problem Description Ignatius花了一个星期的时间终于找到了传说中的宝藏,宝藏被放在一个房间里,房间的门用密码锁起来了,在门旁边的墙上有一些关于密码的提示信息: 密码是一个C进制的

[BZOJ 1054][HAOI 2008]移动玩具(BFS+判重)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1054 真是水题,感谢HAOI送的福利样例23333 裸BFS,用string做判重,会八数码就会这题. 注意由于队列中状态数很多,一定要把队列的数组开大点!!! #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <