• P1126 机器人搬重物


    题目大意:

    一个网格,机器人只能走格点,不能走框内,而障碍物是在框内的,机器人有五个指令:向前走一步、向前走两步、向前走三步、向左转、向右转,每个指令都需要花费1秒中的时间,计算机器人从起点到终点花费的最少时间(原题链接:P1126 机器人搬重物
    如图(图片来自洛谷):

    输入格式:

    第一行:(N)(M)表示图大小,接下来(N)行就是图,(0)表示空地,(1)表示障碍物,接下来一行起点(x)(y),终点(xx)(yy),初始方向(dir)(一个大写字母):东(E),南(S),西(W),北(N)

    输出格式:

    一个整数,表示机器人完成任务所需的最少时间。如果无法到达,输出(−1)

    输入:

    9 10
    0 0 0 0 0 0 1 0 0 0
    0 0 0 0 0 0 0 0 1 0
    0 0 0 1 0 0 0 0 0 0
    0 0 1 0 0 0 0 0 0 0
    0 0 0 0 0 0 1 0 0 0
    0 0 0 0 0 1 0 0 0 0
    0 0 0 1 1 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0
    1 0 0 0 0 0 0 0 1 0
    7 2 2 7 S

    输出:

    12

    思路:

    第一个问题:机器人只能走格点,而障碍物在框内,换句话说就是障碍物的四个顶点机器人都是不可以走的,因此我们可以干脆把原来的图转化成格点图(这个我在做的时候是想到了的。。。)。
    转化这个操作在草稿纸上模拟一下就懂了,于是就有了下边的代码。

    if(g[i][j] == 1) //转化
    {
         mp[i-1][j-1] = 1;
         mp[i-1][j] = 1;
         mp[i][j-1] = 1;
         mp[i][j] = 1;
    }
    

    再引用一个图吧~~(来自洛谷题解),

    转化后了,就相当于这样。
    (BFS)还是挺好写的,这图难就难在方向处理,太蛋疼了,看了那位仁兄的题解才懂的。
    大的想法:先枚举四个方向,然后再枚举走1~3步,要注意的是我们切换方向的时候也需要用最短的时间来切换,于是我们就用一个数组来存从当前方向转向到最优方向花的时间,代码如下:

    mindi[5] = {0, 1, 2, 1, 0}
    

    再再引用一个图吧~~,比如我们在正北方向,那么转到最优方向的时间如下(题目中我们默认它顺时针转动,不过逆时针也可以啦):

    再就是转向问题了(用(i)枚举四个方向):用(fdi)数组存方向,用(ffdi)存转动i后的方向。

    int fdi[5] = {0, 1, 4, 2, 3}
    ffdi[5] = {0, 1, 3, 4, 2}
    

    相关代码

    int ffx = ffdi[t.di] + i; //顺时针旋转i次后后到达的方向编号
    if(ffx == 5) ffx = 1;
    else if(ffx == 6) ffx = 2;
    else if(ffx == 7) ffx = 3;
    else if(ffx == 8) ffx = 4;
    ffx = fdi[ffx];
    

    比如当前在东(E)方向,也就是方向:(4)(ffx = ffdi[t.di] + i = ffdi[4] + 1 = 3), (ffx = fdi[3] = 2),顺时针转一下到方向(2),即南(S)方向。

    再枚举1~3步:
    类似于(Dijkstra)的判断:(t.res+spin+1 < dist[nx][ny] || dist[nx][ny] == -1 ) && mp[nx][ny] == 0 如果距离更小 或者 没有到达过 并且点可走:更新距离,入队列。

    总代码:

    #include <iostream>
    #include <queue>
    #include <cstring>
    
    using namespace std;
    
    const int N = 55, M = 100;
    
    int g[N][N], mp[M][M];
    int n, m;
    int x, y, xx, yy;
    int dist[M][M];
    int mindi[5] = {0, 1, 2, 1, 0};
    int fdi[5] = {0, 1, 4, 2, 3}, ffdi[5] = {0, 1, 3, 4, 2}; //
    int fx[5] = {0, -1, 1, 0, 0}, fy[5] = {0, 0, 0, -1, 1}; //只走x方向 或者只走y方向
    int dir; //起点方向
    
    struct node
    {
        int sx, sy;
        int di;
        int res;
    };
    
    void direction(char *op)
    {
        switch(*op)
        {
            case 'N': dir = 1; break;
            case 'S': dir = 2; break;
            case 'W': dir = 3; break;
            case 'E': dir = 4; break;
        }
        return;
    }
    
    void bfs(int x, int y)
    {
        node start; //起点
        start.sx = x, start.sy = y, start.di = dir, start.res = 0;
        memset(dist, -1, sizeof dist);
        queue<node> q;
        q.push(start);
        dist[x][y] = 0;
    
        while(q.size())
        {
            node d;
            auto t = q.front();
            q.pop();
    
            for(int i = 1; i <= 4; i++)
            {
                int spin = mindi[i]; //切换方向的最短旋转次数
    
                int ffx = ffdi[t.di] + i; //顺时针旋转i次后后到达的方向编号
                if(ffx == 5) ffx = 1;
                else if(ffx == 6) ffx = 2;
                else if(ffx == 7) ffx = 3;
                else if(ffx == 8) ffx = 4;
                ffx = fdi[ffx];
                for(int j = 1; j <= 3; j++) //走1~3步
                {
                    int nx = t.sx + fx[ffx] * j, ny = t.sy + fy[ffx] * j;
                    if(nx <= 0 || nx >= n || ny <= 0 || ny >= m || ((nx == x) && (ny == y)) || mp[nx][ny] == 1) 
                        break; //起点或者障碍物或者越界
                    if((t.res+spin+1 < dist[nx][ny] || dist[nx][ny] == -1 ) &&  mp[nx][ny] == 0)
                    {
                        d.sx = nx, d.sy = ny, d.di = ffx, d.res = t.res + spin + 1;
                        dist[nx][ny] = d.res;
                        q.push(d);
                    }
                }
            }
        }    
    }
    
    int main()
    {
        cin >> n >> m;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                cin >> g[i][j];
                if(g[i][j] == 1) //转化
                {
                    mp[i-1][j-1] = 1;
                    mp[i-1][j] = 1;
                    mp[i][j-1] = 1;
                    mp[i][j] = 1;
                }
            }
        }
        char op[2];
        cin >> x >> y >> xx >> yy >> op;
        direction(op);
        bfs(x, y);
        
        cout << dist[xx][yy] << endl;
        system("pause");
        return 0;
    }
    
    

    这道绿题花了两个小时的时间(AC),然后写了一个小时的博客,太菜了,太菜了。。。

  • 相关阅读:
    std::bind 详解及参数解析
    c++ 静态类成员函数(static member function) vs 名字空间 (namespace)
    继续进发
    lua闭包
    Mysql按时间段分组查询来统计会员的个数
    linux安装配置sendmail实现邮件发送
    Javascript验证用户输入URL地址是否正确
    php返回json数据函数例子
    ArrayList与List对象用法与区别
    java 获取数组(二维数组)长度实例程序
  • 原文地址:https://www.cnblogs.com/ZhengLijie/p/13552346.html
Copyright © 2020-2023  润新知