zoukankan      html  css  js  c++  java
  • UVA1714 Keyboarding

    传送门

    坑很多的一题

    这里要感谢crk大佬提前帮我把所有的坑都踩了一遍...233

    讲一下题目的意思:

    给你一个神奇的 r*c 的键盘 (r,c<=50)

    上面有大写的字母,数字,' - '号 和 ' * ' 号

    有一个光标在键盘上

    一开始在左上角,每次可以对光标进行一次操作:

    向上,向下,向左,向右 和打印当前光标所在的字符

    然后给你一个字符串(保证经过一些操作后可以打出来)

    问你最少要几次操作才能打出给定的字符串

    坑点:

    1.在键盘上可能有很多的位置是同一种字符

    2.如果从当前字符向某一个方向走,下一个字符和上一个字符一样

    那么就自动跳过,直到找到下一个不一样的字符,而且只算走了一步

    3.最后要在键盘上多选择一个 ' * ' 字符,表示回车

    4.多组数据

    数据这么小,肯定考虑搜索

    预处理出每个点向4个方向到达的点

    字符转成数字处理

    用的是广搜,注意一次只走一步

    不能走完了再选(算两步)

    要分开来考虑

    大概就这样吧,实现起来也不难

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<map>
    #include<queue>
    using namespace std;
    map <char,int> Map;//用map把字符转成数字
    int n,m,ans;
    int mp[57][57],xx[4]={0,1,0,-1},yy[4]={1,0,-1,0};//mp存键盘状态
    int nex[57][57][4][2];//nex存每个点向4个方向走,走到的点的横坐标和纵坐标
    inline void premap()//预处理map
    {
        for(int i=1;i<=10;i++) Map[(char)('0'+i-1)]=i;
        for(int i=0;i<=25;i++) Map[(char)('A'+i)]=i+11;
        Map['-']=37; Map['*']=38;
    }
    inline void prenex()//预处理nex
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                for(int k=0;k<4;k++)
                {
                    int x=i+xx[k],y=j+yy[k];
                    while(mp[i][j]==mp[x][y]) x+=xx[k],y+=yy[k];//如果相同就继续走
                    nex[i][j][k][0]=x; nex[i][j][k][1]=y;
                }
    }
    struct node
    {
        int x,y,stp,dis;
        //x,y存横纵坐标,stp存当前已经选了几个字符,dis表示进行了几次操作
    };//广搜的队列里每个点的内容
    int lst[10007],vis[57][57],len;
    //lst存给定的字符串转成数字后的情况
    //vis是记忆化数组,存走到点 i j 时选择的字符最多为多少
    inline void bfs()
    {
        queue <node> q;//每次都重新开一个队列,如果重复用也可以,但是要注意清空
        q.push( (node){1,1,0,0} );//把初始状态压入队列
        while(!q.empty())
        {
            node u=q.front(); q.pop();
            if(mp[u.x][u.y]==lst[u.stp])//如果当前光标所在的字符是当前想要的字符
            {
                if(u.stp==len)//如果是最后一个字符,就代表找到了最少步数
                {
                    ans=u.dis+1;//注意+1
                    return;
                }
                //否则
                u.stp++; u.dis++;//选择此字符
                vis[u.x][u.y]=u.stp;//更新vis
                q.push(u);//重新加入队列
            }
            else//如果不是想要的字符
            {
                int x,y;
                for(int k=0;k<4;k++)//尝试向4个方向移动
                {
                    x=nex[u.x][u.y][k][0]; y=nex[u.x][u.y][k][1];
                    if(x<1||x>n||y<1||y>m) continue;//判断越界
                    if(vis[x][y]>=u.stp) continue;//剪枝
                    vis[x][y]=u.stp;
                    q.push( (node){x,y,u.stp,u.dis+1} );//新状态加入队列
                }
            }
        }
    }
    char ch[10007];
    int main()
    {
        premap();
        while(scanf("%d",&n)!=EOF)
        {
            memset(nex,0,sizeof(nex));
            memset(mp,0,sizeof(mp));
            memset(lst,0,sizeof(lst));
            memset(vis,-1,sizeof(vis));//注意初始化
            ans=0;
            scanf("%d",&m);
            for(int i=1;i<=n;i++)
            {
                scanf("%s",ch);
                for(int j=0;j<m;j++)
                    mp[i][j+1]=Map[ch[j]];//读入键盘并转成数字
            }
            scanf("%s",ch); len=strlen(ch);
            for(int i=0;i<len;i++) lst[i]=Map[ch[i]];//读入字符串并转成数字
            lst[len]=38;//最后要加一个'*'号
            prenex();
            bfs();
            cout<<ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    第26月第26天 Domain=AVFoundationErrorDomain Code=-11850
    第26月第25天 ubuntu openjdk-8-jdk jretty
    第26月第23天 nsobject 单例 CFAbsoluteTimeGetCurrent
    第26月第22天 iOS瘦身之armv7 armv7s arm64选用 iOS crash
    第26月第20天 springboot
    第26月第18天 mybatis_spring_mvc pom
    python中的字符数字之间的转换函数
    python if else elif statement
    python 赋值魔法
    python print import使用
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9627060.html
Copyright © 2011-2022 走看看