首页 > 其他分享 >bfs 与优先队列————洛谷p1126(历经两个小时总算AC了,哭晕)

bfs 与优先队列————洛谷p1126(历经两个小时总算AC了,哭晕)

时间:2024-09-25 21:23:36浏览次数:1  
标签:nxt AC now 洛谷 int 机器人 bfs tm include

机器人搬重物

题目描述

机器人移动学会(RMI)现在正尝试用机器人搬运物品。机器人的形状是一个直径 \(1.6\) 米的球。在试验阶段,机器人被用于在一个储藏室中搬运货物。储藏室是一个 \(N\times M\) 的网格,有些格子为不可移动的障碍。机器人的中心总是在格点上,当然,机器人必须在最短的时间内把物品搬运到指定的地方。机器人接受的指令有:

  • 向前移动 \(1\) 步(Creep);
  • 向前移动 \(2\) 步(Walk);
  • 向前移动 \(3\) 步(Run);
  • 向左转(Left);
  • 向右转(Right)。

每个指令所需要的时间为 \(1\) 秒。请你计算一下机器人完成任务所需的最少时间。

输入格式

第一行为两个正整数 \(N,M\ (1\le N,M\le50)\),下面 \(N\) 行是储藏室的构造,\(0\) 表示无障碍,\(1\) 表示有障碍,数字之间用一个空格隔开。接着一行有 \(4\) 个整数和 \(1\) 个大写字母,分别为起始点和目标点左上角网格的行与列,起始时的面对方向(东 \(\tt E\),南 \(\tt S\),西 \(\tt W\),北 \(\tt N\)),数与数,数与字母之间均用一个空格隔开。终点的面向方向是任意的。

输出格式

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

样例 #1

样例输入 #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

样例输出 #1

12

本题是一个很典型的dfs题,但坑点很多,一连坑了我好多次。。。。不嘻嘻

  • 首先就是计算转向的时间,我将NSWE是个方向代数为1,2,3,4,然后取他们差的绝对值,代表转向的时间,但是没有注意到4和1相差3,但实际上只用1秒,这个错纯属犯病。。。写太快了.
  • 然后就是如何将输入的方格图转化为格点图,这个要画出图来
  • 之后就是机器人走三步的时候有可能跳过障碍,但这是不允许的,所以需要剪枝
  • 最后就是要用优先队列优先取出tm最小的节点
  • 还有就是它测试用例的一些毒点,比如起点卡墙里(@-@!
    具体细节在代码里

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<cmath>
#include<iomanip>
using namespace std;
int a[55][55]; //存储方格图
long long mp[55][55]; //存储格点图,即机器人行走的图
int dis[55][55]; //用于记录机器人到该格点的最短时间
int n, m;  //方格图的尺寸
int x1, y11, x2, y2; //记录起点终点坐标
int sto;//起点的方向 
string ch;//读入起点的方向 

struct node
{
    int x;
    int y;//当前点的坐标 
    int to;//1=>N(上) 2=>E(右) 3=>S(下) 4=>W(左) 方向编号 
    int tm;//从起点到当前点的最短时间 
    bool operator < (node a)const {
        return tm > a.tm;
    }
    //stl中优先队列默认优先取出最大值,所以要重载运算符,保证每次取出的都是代价最小的元素
};
priority_queue<node> que;//优先队列
node now, nxt;

int dx[] = { 0, -1,0,1,0 };
int dy[] = { 0, 0,1,0,-1 };

int abs(int a, int b) {
    return a > b ? a - b : b - a;
}

int calchange(int now, int aft) {
    //注意这个情况
    if (abs(now, aft) == 3) {
        return 1;
    }
    else {
        return abs(now, aft);
    }
}

void readto()
{
    switch (ch[0])
    {
    case 'N': sto = 1; break;
    case 'S': sto = 3; break;
    case 'W': sto = 4; break;
    case 'E': sto = 2; break;
    }
    return;
}

void change()
{
    //把边框全部置为1,因为机器人有宽度,不能出现在那里
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= m; ++j)
        {
            if (a[i][j] == 1)//如果当前格为障碍物,则它的四个顶点都不能走 
            {
                mp[i + 1][j] = 1;
                mp[i][j + 1] = 1;
                mp[i + 1][j + 1] = 1;
                mp[i][j] = 1;
            }
            if (i == 1 || j == 1) {
                mp[i][j] = 1;
            }
            if (i == n || j == m) {
                mp[i + 1][j + 1] = 1;
            }
        }
    }
    mp[n + 1][1] = 1;
    mp[1][m + 1] = 1;
}

void bfs() {
    
    dis[x1+1][y11+1] = 0;
    node fir;
    fir.x = x1+1;
    fir.y = y11+1;
    fir.to = sto;
    fir.tm = 0;
    que.push(fir);
    int changecost = 0;
    while (!que.empty()) {
        now = que.top();
        //这个是打印路径的代码
        //cout << now.x << " " << now.y << " " << now.to << " " << now.tm << endl;
        if (now.x == x2+1 && now.y == y2+1) break;  //剪枝
        que.pop();
        if (now.tm > dis[now.x][now.y]) continue;  //剪枝,这个可不加,好像没用
        //遍历四个方向
        for (int i = 1; i <= 4; i++) {
            changecost = calchange(now.to, i);
            //三种移动方式
            for (int j = 1; j <= 3; j++) {
                nxt.x = now.x + dx[i] * j;
                nxt.y = now.y + dy[i] * j;
                //if (mp[nxt.x][nxt.y] == 1 && j==1 || mp[nxt.x][nxt.y] == 1 && j == 2) break;
                if (nxt.x <= 1 || nxt.x > n || nxt.y <= 1 || nxt.y > m || mp[nxt.x][nxt.y] == 1) break;  //剪枝,这个边界判断最好对着图来
                nxt.to = i;
                nxt.tm = now.tm + 1 + changecost;
                if (dis[nxt.x][nxt.y] > nxt.tm) {
                    dis[nxt.x][nxt.y] = nxt.tm;
                    que.push(nxt);
                }
            }
        }
    }
}
int main()
{
    memset(dis, 1061109567, sizeof(dis));
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= m; ++j)
        {
            scanf("%d", &a[i][j]);
        }
    }
    cin >> x1 >> y11 >> x2 >> y2;  //在c++中y1是个函数,所以要换一个
    cin >> ch;
    readto();//判断ch代表的方向 
    change();//把方格地图转化为机器人可以走的格点地图
    //特判一下,防止依赖就卡墙,或者终点卡墙,这个起点和终点的索引最好对着图来
    if (mp[x1 + 1][y11 + 1] == 1 || mp[x2+1][y2+1]==1) {
        cout << -1;
        return 0;
    }
    bfs();
    //这个是打印格点图的代码,可以打印出来看看
    /*for (int i = 1; i <= n + 1; i++) {
        for (int j = 1; j <= m + 1; j++) {
            cout << mp[i][j] << " ";
        }
        cout << endl;
    }*/
    if (dis[x2+1][y2+1] == 1061109567) {
        cout << -1;
    }
    else {
        cout << dis[x2 + 1][y2 + 1];
    }
}

标签:nxt,AC,now,洛谷,int,机器人,bfs,tm,include
From: https://www.cnblogs.com/oQAQo/p/18432243

相关文章

  • 【linux】cent7安装nmon(arm架构,mac虚拟机)
    因为nmon最新版不支持arm架构,所以需要手动下载源码和编译文件手动生成可执行文件mkdir-p/usr/local/tools/nmoncd/usr/local/tools/nmon1、下载源码地址:https://nmon.sourceforge.io/pmwiki.php?n=Site.CompilingNmonwget http://sourceforge.net/projects/nmon/files/lm......
  • 题解 洛谷P3398 仓鼠找 sugar
    原题链接:P3398仓鼠找sugar题解里大部分都是用的lca,然而我看不懂那些关于lca的性质是怎么证明出来的。不过这题可以直接用树链剖分来写,把模板套上去就好了。题意为查找两条路径是否存在公共点,我们只需要把其中一条路径上的点都赋值为1,然后查询另一条路径上的点的总和,如果总和......
  • 列序号括(bracket)
    列序号括(bracket)题面在比赛下发文件里。给你一个括号序列,你可以删除\(i,j\)当\(i<j\)且\(s_i=\)(,\(s_j=\))。问可以形成的字典序最小的括号序列是什么。首先我们要有一点贪心地考虑什么时候我们才会删除一对括号。如果我们要删除的一对括号中间有东西没有被删除,若中间有)......
  • SBB Activity Context Interface (ACI) object 和 Generic Activity Context Interfac
    在JAINSLEE中,SBBActivityContextInterface(ACI)object和GenericActivityContextInterfaceobject的使用主要取决于应用场景的需求、活动的复杂性以及是否需要对特定活动类型进行精确控制。为了更好地理解它们的使用场景、选择依据以及如何在项目中使用,我将详......
  • Android 移动应用开发基础案例教程——Activity的跳转
    一、Activity的创建1、创建一个新项目点击Flie--New--NewProject点击EmptyViewsActivity点击Next根据需要可修改项目名称,这里我重命名为CycActivity,然后点击Finish即可完成创建新项目。2、SecondActivity的创建点击java--->com.example.cycactivity,右键new--->A......
  • 【AI换脸王教程】升级Facefusion3.0整合包,换脸+表情修改,本地部署永久不限使用
    你是否想过瞬间变脸于多张图片之间,甚至在热门视频中“穿越”成主角?又或者你还在因请真人模特、拍实景图、请剪辑师,花了一大半制作费用?GPT-4已经被称为最像“人”的AI,但你还没玩透AI?自媒体/电商从业者都想借助AI解放双手,降本增效,但却不知如何下手?今天揭秘的这款AI神器—FaceFusion3......
  • 110.109 Introductory Financial Accounting
    110.109Introductory FinancialAccountingAssessment3 BookletDistanceandInternalSemester2– 2024IMPORTANT INFORMATIONThis is an electronic assessment and must be completed in the “Assessment 3 Answer Workbook” – Excel temp......
  • Luogu_P10977(AcWing_299) Cut the Sequence 题解
    解题思路考虑线性dp。首先如果存在\(a_i>m\),那肯定不满足条件,输出\(-1\)。设\(f_i\)表示前\(i\)个数分成若干段,然后每段最大数之和,其中每段内的整数之和不超过\(m\)。\(f_i\)肯定是由\(f_j\)(\(1\lej<i\))转移过来的,也就是前\(j\)个数分好后再加上\((j,i]\)这一......
  • 安装memcache集群管理工具
    安装memcache集群管理工具magent一、安装libeventtarxflibevent-2.0.20-stable.tar.gzcdlibevent-2.0.20./configure--prefix=/usr/local/libeventmake&&makeinstallecho"/usr/local/libevent/lib">/etc/ld.so.conf.d/libevent.confldco......
  • P8906 [USACO22DEC] Breakdown P 题解
    P8906[USACO22DEC]BreakdownP题解显然的套路是删边转化为加边。考虑到维护整条路径不好维护,于是考虑转化维护\(f_{i,k},g_{i,k}\)分别表示\(1,n\)到\(i\)走了\(k\)步时的最短路。那么此时\(k\le4\)。我们先考虑\(f\)的转移,\(g\)的转移是等价的。那么对于\((......