洛谷P1126-机器人搬重物-BFS/SPFA

本文介绍了解决洛谷P1126-机器人搬重物问题的方法,通过BFS和SPFA算法实现机器人在网格中避开障碍物搬运物品,并详细解释了如何将该问题建模为图并进行搜索。

洛谷P1126-机器人搬重物-BFS/SPFA

Description

机器人移动学会(RMI)现在正尝试用机器人搬运物品。机器人的形状是一个直径1.6米的球。在试验阶段,机器人被用于在一个储藏室中搬运货物。储藏室是一个N*M的网格,有些格子为不可移动的障碍。机器人的中心总是在格点上,当然,机器人必须在最短的时间内把物品搬运到指定的地方。机器人接受的指令有:向前移动1步(Creep);向前移动2步(Walk);向前移动3步(Run);向左转(Left);向右转(Right)。每个指令所需要的时间为1秒。请你计算一下机器人完成任务所需的最少时间。

Input

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

Output

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

Sample Input

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

Sample Output

12

Hint

img

思路

很明显可以用BFS来解决,不过今天是最短路专题,选这个就是因为其实很大一部分的BFS都可以转化为SPFA来解决,借用大佬的讲解说一下建图思路

很显然,这个题目是一个搜索,我们可以用i,j,k来唯一标识它的状态,i表示行,j表示列,k表示方向(自己定义即可),对于每一个状态,有5种转移方式(左转,右转,前1,前2,前3),而这5种转移是等价的(均耗费时间1),因此可以很好的用广度优先搜索来解决(广搜是基于路径相等的一种搜索,在这里它搜索的不再是点,而是加上方向共同表示的状态),由于边权均为1 ,所以先搜到的状态一定是时间最少的,它不用再入队列。而对于不等价的情况(转移时时间不都是1),或是有其他转换的更复杂的情况,搜索是无法解决的,这里主要讲一下图的构建。

一个状态可以向左转,向右转,进1,2,3,所以把每个状态与其可转移的状态连接,边权赋为所需时间,

每一个状态即为图中的点,为了处理简便,我们用一个单独的数代表i,j,k,这里可以用放缩,即定义

s=x*i+y*j+k,做到可以唯一标识每一个状态; 特别注意,这是一个有向图,你不能倒着走 时间复杂度:50*50*4 共10000个状态,每个点最多5条边,边数为50000,SPFA可以承受!

注意初始化,不能达到的点不再处理!

AC代码

#include <iostream>
#include <queue>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <string>
#define LL long long
#define ULL unsigned long long
#define mem(a,n) memset(a,n,sizeof(a))
#define fread freopen("in.txt","r",stdin)
#define fwrite freopen("out.txt","w",stdout)
#define N 1010
#define INF 0x3f3f3f3f
#define eps 1e-9
using namespace std;
const int xx[4]={-1,0,1,0};
const int yy[4]={0,1,0,-1};
struct Con{
    int x,y,dir;
    Con(int a,int b,int c):x(a),y(b),dir(c){}
};
struct Edge{
    Con from,to;
    int dist;
    Edge(Con u,Con v,int d):from(u),to(v),dist(d){};
};
struct SPFA{
    vector<Edge> edges;
    vector<int> G[110][110][4];
    bool mp[110][110];
    bool inque[110][110][4];
    int d[110][110][4];
    int cnt[110][110][4];
    int n,m;

    bool valid(int x,int y){
        return x>0&&y>0&&x<n&&y<m&&!mp[x][y];
    }

    void init(int n,int m){
        this->n=n;
        this->m=m;
        int temp;
        mem(mp,0);
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                scanf("%d",&temp);
                if(temp){
                    mp[i][j]=mp[i+1][j]=mp[i][j+1]=mp[i+1][j+1]=true;
                }
            }
        }
        for(int i=0;i<55;++i){
            for(int j=0;j<55;++j){
                for(int k=0;k<4;++k){
                    G[i][j][k].clear();
                }
            }
        }
        bool canwalk; 
        edges.clear();
        for(int i=1;i<n;++i){
            for(int j=1;j<m;++j){
                if(!mp[i][j]){
                    for(int k=0;k<4;++k){
                        this->AddEdge(Con(i,j,k),Con(i,j,(k+1)%4),1);
                        this->AddEdge(Con(i,j,k),Con(i,j,(k+3)%4),1);
                        canwalk=true;
                        for(int len=1;canwalk&&len<4;++len){
                            if(valid(i+yy[k]*len,j+xx[k]*len)){
                                this->AddEdge(Con(i,j,k),Con(i+yy[k]*len,j+xx[k]*len,k),1);
                            }else{
                                canwalk=false;
                            }
                        }
                    }
                }
            }
        }
    }

    void AddEdge(Con from,Con to,int dist){
        edges.push_back(Edge(from,to,dist));
        m=edges.size();
        G[from.x][from.y][from.dir].push_back(m-1);
    }

    bool spfa(Con s){
        queue<Con> que;
        memset(inque,0,sizeof(inque));
        memset(cnt,0,sizeof(cnt));
        memset(d,INF,sizeof(d));
        que.push(s);
        d[s.x][s.y][s.dir]=0;
        while(!que.empty()){
            Con temp=que.front();
            if(cnt[temp.x][temp.y][temp.dir]==n){
                return true;
            }
            que.pop();
            inque[temp.x][temp.y][temp.dir]=false;
            for(int i=0;i<G[temp.x][temp.y][temp.dir].size();++i){
                Edge &e=edges[G[temp.x][temp.y][temp.dir][i]];
                if(d[e.to.x][e.to.y][e.to.dir]>d[temp.x][temp.y][temp.dir]+e.dist){
                    d[e.to.x][e.to.y][e.to.dir]=d[temp.x][temp.y][temp.dir]+e.dist;
                    if(!inque[e.to.x][e.to.y][e.to.dir]){
                        que.push(e.to);
                        inque[e.to.x][e.to.y][e.to.dir]=true;
                        if(++cnt[e.to.x][e.to.y][e.to.dir]>=n)  return true;
                    }
                }
            }
        }
        return false;
    }
};
SPFA SMF;
int main()
{
    int n,m,u,v,c,d,dir;
    char s;
    while(~scanf("%d%d",&n,&m)){
        SMF.init(n,m);
        scanf("%d%d%d%d%*c%c",&u,&v,&c,&d,&s);
        switch(s){
            case 'S':dir=1;
                break;
            case 'W':dir=0;
                break;
            case 'N':dir=3;
                break;
            case 'E':dir=2;
                break;
        }
        SMF.spfa(Con(u,v,dir));
        int ans=INF;
        for(int i=0;i<4;++i){
            ans=min(ans,SMF.d[c][d][i]);
        }
        printf("%d\n",(ans==INF?-1:ans));
    }
    return 0;
}
<think>我们正在处理用户的问题:执行Hadoop相关脚本时出现'./sbin/start-bfs.sh: No such file or directory'错误,以及启动后jps显示的进程情况。 首先,用户执行了`./sbin/start-bfs.sh`,但提示没有这个文件或目录。实际上,在Hadoop中,启动HDFS的脚本通常是`start-dfs.sh`,而启动YARN的脚本是`start-yarn.sh`。Hadoop并没有一个名为`start-bfs.sh`的脚本。因此,这个错误很可能是因为脚本名称错误。 其次,用户提到启动dfs和yarn后,使用jps显示有NodeManager、ResourceManager和Jps进程。这里需要注意: - 启动dfs应该会启动NameNode, DataNode, SecondaryNameNode(非HA模式)等进程。 - 启动yarn会启动ResourceManager和NodeManager。 用户jps显示只有NodeManager、ResourceManager和Jps,说明没有启动HDFS的进程(比如NameNode, DataNode等)。因此,虽然YARN启动了,但HDFS并没有启动。 所以,问题有两个: 1. 用户执行了错误的脚本名称(start-bfs.sh)导致HDFS启动失败。 2. 用户手动启动了yarn(可能是通过`start-yarn.sh`)所以yarn的进程存在,但HDFS进程缺失。 解决方案: 1. 更正脚本名称:使用`start-dfs.sh`来启动HDFS,使用`start-yarn.sh`来启动YARN。 2. 检查Hadoop的安装目录,确认sbin目录下确实存在`start-dfs.sh`和`start-yarn.sh`脚本。 3. 启动后再次用jps检查所有节点上的进程。 另外,根据用户提供的引用[2]中,有类似的操作: - `sbin/start-dfs.sh` - `hadoop fs -mkdir /directory` 因此,我们指导用户使用正确的脚本。 步骤: 1. 切换到Hadoop安装目录(例如:`/usr/local/hadoop`) 2. 启动HDFS:`./sbin/start-dfs.sh` 3. 启动YARN:`./sbin/start-yarn.sh` 4. 使用`jps`命令检查进程,应该会看到至少以下进程: - NameNode - DataNode(在数据节点上) - SecondaryNameNode(如果配置了的话,非HA模式) - ResourceManager - NodeManager - 以及其他可能的进程(如JournalNode, DFSZKFailoverController等,如果配置了HA) 注意:如果是在单节点伪分布式上,那么在一个节点上应该看到NameNode, DataNode, SecondaryNameNode(如果配置了), ResourceManager, NodeManager等。 如果启动dfs时遇到问题,比如提示JAVA_HOME未设置,可以参考引用[1]中提到的设置JAVA_HOME。 引用[3]中给出了一个正常启动后jps显示的进程列表,包括DataNode, NameNode, ResourceManager, NodeManager等,可以作为参考。 用户的问题中另一个细节:用户执行了`./sbin/start-bfs.sh`,这可能是因为用户混淆了HDFS(Hadoop Distributed File System)和BFS(可能代表其他东西,但在Hadoop中通常不会用BFS)。所以,必须使用正确的脚本名称。 总结回答结构: 1. 指出错误原因:脚本名称错误,Hadoop中没有`start-bfs.sh`。 2. 给出正确的启动脚本名称和步骤。 3. 分析当前jps显示的进程情况,指出缺少HDFS相关进程。 4. 给出完整的启动步骤和预期结果。 5. 如果启动过程中出现其他错误(如JAVA_HOME未设置),提供解决方向。 生成相关问题: 1. Hadoop中启动HDFS和YARN的正确命令是什么? 2. 如何在Hadoop中配置JAVA_HOME环境变量? 3. Hadoop高可用(HA)模式下启动脚本有什么不同? 注意:在回答中适当引用用户提供的引用标记。 </think>### Hadoop启动脚本错误分析与解决指南 #### 🔍 问题分析 1. **脚本名称错误** Hadoop官方脚本名称为 `start-dfs.sh`(HDFS启动)和 `start-yarn.sh`(YARN启动),**不存在 `start-bfs.sh` 脚本**。错误提示直接表明执行了错误命令: ```bash ./sbin/start-bfs.sh # 错误命令 ./sbin/start-dfs.sh # 正确命令[^2] ``` 2. **进程状态分析** 当前 `jps` 显示仅存在 YARN 相关进程: - ✅ `NodeManager`:YARN工作节点 - ✅ `ResourceManager`:YARN资源调度器 - ❌ **缺少 HDFS 核心进程**: - `NameNode`:HDFS元数据管理 - `DataNode`:数据存储节点 - `SecondaryNameNode`:检查点服务 3. **根本原因** **HDFS 未正常启动**,导致文件系统服务不可用(YARN可独立运行但依赖HDFS存储数据) #### 🛠️ 解决步骤 **步骤1:执行正确启动命令** ```bash # 启动HDFS ./sbin/start-dfs.sh # 启动YARN ./sbin/start-yarn.sh # 完整启动脚本参考[^2] /home/xikuang/bin/myhadoop.sh start ``` **步骤2:验证进程状态** ```bash jps # 应包含以下核心进程 ``` | 必要进程 | 说明 | 状态指示 | |---------|------|---------| | NameNode | HDFS主节点 | ✅ 必须存在 | | DataNode | 数据存储节点 | ✅ 至少1个 | | ResourceManager | YARN主节点 | ✅ 当前存在 | | NodeManager | YARN工作节点 | ✅ 当前存在 | | SecondaryNameNode | 元数据备份 | ️ 非必须但推荐 | **步骤3:检查配置文件** 确认 Hadoop 环境变量配置: ```bash # 检查JAVA_HOME设置 grep JAVA_HOME etc/hadoop/hadoop-env.sh # 应显示:export JAVA_HOME=/your/java/path[^1][^4] ``` **步骤4:端口访问验证** - HDFS 状态:`http://<namenode_ip>:9870` - YARN 状态:`http://<resourcemanager_ip>:8088`[^3] #### ⚠️ 注意事项 1. **权限问题** 确保使用 `hadoop` 用户操作: ```bash sudo -u hadoop ./sbin/start-dfs.sh # 切换用户执行 ``` 2. **日志排查** 若启动失败,检查日志: ```bash tail -n 100 logs/hadoop-*-namenode-*.log ``` 3. **目录初始化** 首次启动需格式化: ```bash hdfs namenode -format # 仅限首次初始化[^3] ``` #### ✅ 预期正常状态 成功执行后 `jps` 应显示: ```bash 27450 NameNode # HDFS主节点 27720 DataNode # 数据节点 28189 ResourceManager # YARN主节点 28365 NodeManager # YARN工作节点 28512 SecondaryNameNode # 检查点服务 28753 Jps # Java进程查看器 ``` > 📌 提示:Hadoop 2.x+ 高可用(HA)模式下还需 `JournalNode` 和 `DFSZKFailoverController` 进程[^3][^5]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值