• 迷宫广搜


    上学期学了C,这学期学C++。感觉最难的还是算法,上周作业的一道广搜题是我第一次接触广搜,由于第一学期刚学编程就接触的太多的算法难题,不禁对代码产生畏惧,不过还好没有放弃,虽然算法很难,但我慢慢找到了一点学数学时的乐趣。
    先介绍一下这道未来的我看过来会觉得很简单一道题吧
    迷宫广搜
    You are provided a maze(迷宫), and you need to program to find the least steps to walk from the start to the end.And you can only walk in four directions:up, down,left, right.
    There will only be 5 kinds of characters in the maze.The meaning of each is as followed.
    '#' is for rock, which you can not walk through.
    'S' is for start.
    'E' is for end.
    '.' is for road.
    '!' is for magma(岩浆),which you can not walk through.
    Input
    n,m represent the maze is a nxm maze.(n rows, m columnsm,0 <= 21).
    Then is the maze.
    e.g.
    55
    #####
    #S..#
    #.!.#
    #.#E#
    #####
    Output
    You need to give the least steps to walk from start to the end.If it doesn't e xist, then output -1.
    e.g.(for the example in input)
    4

    任性的我一开始没有按照hint去找广搜,因为以前做过一道深搜题也是关于迷宫的,于是一开始我就按照深搜的方法去找最短路径
    ------有些地方有错,由于从我的新浪博客上搬运过来的,不知道为什么会变成这个样子~_~
    #include
    #include
    #include
    using namespace std;
    int least_step(char (*p)[21], int n, int m);//深搜寻找最短路径
    int main() {
    	int n, m;
    	char maze[21][21];
    	for (int i = 0; i < 21; i++) {
    		for (int j = 0; j < 21; j++) {
    			maze[i][j] = '#';
    		}
    	}//初始化迷宫格子
    	cin >> n >> m;
    	for (int i = 0; i < n; i++) {
    		for (int j = 0; j < m; j++) {
    			cin >> maze[i][j];
    		}
    	}
    	cout << least_step(maze, n, m) << endl;
    	return 0;
    }
    int least_step(char (*p)[21], int n, int m) {
    	static int len = 0;
    	static priority_queue, greater > len_s;//存储路径.
    	int i, j;
    	for (i = 0; i < n; i++) {
    		for (j = 0; j < m; j++) {
    			if (p[i][j]== 'S')
    				break;
    		}
    		if (p[i][j] == 'S')
    			break;
    	}
    	if (p[i + 1][j] == 'E' && i + 1 < n) {
    		len++; len_s.push(len); len--; return 1;
    	}
    	else if (p[i][j + 1] == 'E' && j + 1 < m) {
    		len++; len_s.push(len); len--; return 1;
    	}
    	else if (p[i][j - 1] == 'E' && j - 1 > 0) {
    		len++; len_s.push(len); len--; return 1;
    	}
    	else if (p[i - 1][j] == 'E' && i - 1 > 0) {
    		len++; len_s.push(len); len--; return 1;
    	}//如果找到了终点就返回
    	if (p[i + 1][j] == '.' && i + 1 < n) {
    		p[i][j] = '#';
    		p[i + 1][j] = 'S';
    		len++;
    		least_step(p, n, m);
    		p[i][j] = 'S';
    		p[i + 1][j] = '.';
    		len--;
    	}
    	if (p[i][j + 1] == '.' && j + 1 < m) {
    		p[i][j] = '#';
    		p[i][j + 1] = 'S';
    		len++;
    		least_step(p, n, m);
    		p[i][j] = 'S';
    		p[i][j + 1] = '.';
    		len--;
    	}
    	if (p[i][j - 1] == '.' && j - 1 > 0) {
    		p[i][j] = '#';
    		p[i][j - 1] = 'S';
    		len++;
    		least_step(p, n, m);
    		p[i][j] = 'S';
    		p[i][j - 1] = '.';
    		len--;
    	}
    	if (p[i - 1][j] == '.' && i - 1 > 0) {
    		p[i][j] = '#';
    		p[i - 1][j] = 'S';
    		len++;
    		least_step(p, n, m);
    		p[i][j] = 'S';
    		p[i - 1][j] = '.';
    		len--;
    	}//按4个方向进行深搜
    	if (len_s.size() != 0)
    	return len_s.top();//最后找到最小的路径
    	else return -1;
    }
    

      


    结果随机数据超时25个
    迷宫广搜
    233333,老子辛辛苦苦打的代码就这样挂了。于是老老实实去找广搜了。于是查了各个博客的方法,查了下深搜广搜,终于发现了这两种方法,并找到了广搜的解决方案。http://yes2.me/archives/424
    于是试着用广搜敲敲。中间的代码就不展示了,最后代码成了这个样子。
    #include
    #include
    using namespace std;
    int least_step(char (*p)[21], int n, int m);
    struct path {
    	path(int a, int b, int c) : x(a), y(b), floor(c) {}
    	int x, y;
    	int floor;//记录当前节点的层数
    };
    int main() {
    	int n, m;
    	char maze[21][21];
    	cin >> n >> m;
    	for (int i = 0; i < n; i++) {
    		for (int j = 0; j < m; j++) {
    			cin >> maze[i][j];
    		}
    	}
    	cout << least_step(maze, n, m) << endl;
    	return 0;
    }
    int least_step(char (*p)[21], int n, int m) {
    	int step = 0, i = 0, j = 0, flag = 1;
    	queue road;
    	for (i = 0; i < n; i++) {
    		for (j = 0; j < m; j++) {
    			if (p[i][j] == 'S') {
    				flag = 0;//便于退出2重循环
    				break;
    			}
    		}
    		if (!flag) break;
    	}
    	road.push(path(i, j, 0));
    	p[road.front().x][road.front().y] = '#';
    	while (1) {
    		if (p[road.front().x][road.front().y + 1] == 'E' &&
    			road.front().y + 1 < m) {
    			step++;
    			return step;
    		}
    		if (p[road.front().x + 1][road.front().y] == 'E' &&
    			road.front().x + 1 < n) {
    			step++;
    			return step;
    		}
    		if (p[road.front().x - 1][road.front().y] == 'E' &&
    			road.front().x - 1 > 0) {
    			step++;
    			return step;
    		}
    		if (p[road.front().x][road.front().y - 1] == 'E' &&
    			road.front().y - 1 > 0) {
    			step++;
    			return step;
    		}//若搜索到终点,则返回步数
    		if (p[road.front().x][road.front().y + 1] == '.' &&
    			road.front().y + 1 < m) {
    				p[road.front().x][road.front().y + 1] = '#';
    				if (road.front().floor == step) {
    					step++;
    				}
    			road.push(path(road.front().x, road.front().y + 1, step));
    		}
    		if (p[road.front().x + 1][road.front().y] == '.' &&
    			road.front().x + 1 < n) {
    			p[road.front().x + 1][road.front().y] = '#';
    			if (road.front().floor == step) {
    				step++;
    			}
    			road.push(path(road.front().x + 1, road.front().y, step));
    		}
    		if (p[road.front().x - 1][road.front().y] == '.' &&
    			road.front().x - 1 > 0) {
    			p[road.front().x - 1][road.front().y] = '#';
    			if (road.front().floor == step) {
    				step++;
    			}
    			road.push(path(road.front().x - 1, road.front().y, step));
    		}
    		if (p[road.front().x][road.front().y - 1] == '.' &&
    			road.front().y - 1 > 0) {
    			p[road.front().x][road.front().y - 1] = '#';
    			if (road.front().floor == step) {
    				step++;
    			}
    			road.push(path(road.front().x, road.front().y - 1, step));
    		}//4个方向去按层寻找,之后同一层的节点不重复加,把找过的节点标志为墙,把 //合适的点压紧队列。
    		road.pop();//搜过一个队头后弹出队列
    		if (road.size() == 0) return -1;//发现队列中没有节点,说明每条路都走到了 //绝境,不能走下去了
    	}
    }
    打的时候很艰辛,主要是层数的记录,我没有想到简单的方法,只是简单的用一个变量记录,然后每次每一次判断看当前节点是不是正在处理的这一层,在决定step是否加1。更傻#的是,之前的函数参数传递还搞了一下,传递2维数组用指针数组,而不是数组指针,而且要把声明部分改掉,不能只改定义部分的接口,因为这个耽误好多时间,看来C没学扎实。。。。
    后来同学问我这道题,当然她自己敲了一下,我看了一下,比我的好多了(后来知道她也是在百度上找了一下)。在此借鉴一下。
    #include
    #include
    #include
    #include
    using namespace std;
    struct Node {
    int x;
    int y;
    int step;
    Node(int x1, int y1, int step1) : x(x1), y(y1), step(step1) {}
    Node() {}
    } s, e;
    int main() {
    int n, m, sx, sy, ex, ey;
    cin >> n;
    cin >> m;
    int i, j;
    int xx, yy;
    bool flag = -1;
    Node node(0, 0, 0);
    char c;
    queue maza;
    int point[100][100];
    bool visit[100][100];
    int d[4][2] = {
    {0, 1} , {1, 0}, {0, -1}, {-1, 0}
    };
    for (i = 0; i < n; i++) {
    for (j = 0; j < m; j++) {
    cin >> c;
    visit[i][j] = 0;
    if (c == 'S') {
    sx = i;
    sy = j;
    point[i][j] = 1;
    } else if (c == 'E') {
    ex = i;
    ey = j;
    point[i][j] = 1;
    } else if(c == '!') {
    point[i][j] = 0;
    } else if (c == '#') {
    point[i][j] = 0;
    }
    else point[i][j] = 1;
    }
    }
    Node s(sx, sy, 0), e(ex, ey, 0);
    maza.push(s);
    while (!maza.empty()) {
    node = maza.front();
    maza.pop();
    if (node.x == e.x && node.y == e.y) {
    cout << node.step << endl;
    flag = 0;
    break;
    }
    visit[node.x][node.y] = 1;
    for (i = 0; i < 4; i++) {
    int x = node.x + d[i][0];
    int y = node.y + d[i][1];
    if (x >= 0 && y >= 0
    && visit[x][y] != 1 && point[x][y] != 0) {
    Node next(x, y, node.step + 1);
    visit[x][y] = 1;
    maza.push(next);
    }
    }
    }
    if (flag != 0)
    cout << -1 << endl;
    }
    关于那个变量作为数组大小的问题也百度了一下,是编译器扩展的问题,本来是不可以这样做的,但是devc++的编译器有编译器扩展支持了这一做法。
    最后给一下TA给的答案,
    #include
    #include
    #include
    #include
    using std::cin;
    using std::cout;
    using std::endl;
    using std::queue;
    int n, m;
    class state {
    private:
    int s_x, s_y;
    int e_x, e_y;
    int step;
    public:
    state() {step = 0;}
    state(int a, int b, int c, int d) {
    s_x = a;
    s_y = b;
    e_x = c;
    e_y = d;
    step = 0;
    }
    bool ismeet();
    bool isvaild();
    friend void judge();
    };
    bool state::ismeet() {
    if (s_x == e_x && s_y == e_y)
    return true;
    else
    return false;
    }
    bool state::isvaild() {
    if (s_x > 0 && s_x <= n && s_y > 0 && s_y <= m)
    return true;
    else
    return false;
    }
    int s_x, s_y, e_x, e_y;
    int mov[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    char aa[21][21];
    bool isvisit[21][21];
    void judge();
    int main() {
    cin >> n >> m;
    memset(isvisit, false, sizeof(isvisit));
    for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
    cin >> aa[i][j];
    if (aa[i][j] == 'S') {
    s_x = i;
    s_y = j;
    aa[i][j] = '.';
    }
    if (aa[i][j] == 'E') {
    e_x = i;
    e_y = j;
    aa[i][j] = '.';
    }
    }
    }
    judge();
    return 0;
    }
    void judge() {
    queue vv;
    vv.push(state(s_x, s_y, e_x, e_y));
    state temp, hold;
    while (!vv.empty()) {
    temp = vv.front();
    vv.pop();
    for (inti = 0; i < 4; i++) {
    hold.s_x = temp.s_x + mov[i][0];
    hold.s_y = temp.s_y + mov[i][1];
    hold.step = temp.step + 1;
    hold.e_x = temp.e_x;
    hold.e_y = temp.e_y;
    if (hold.isvaild() && aa[hold.s_x][hold.s_y] == '.') {
    if (!isvisit[hold.s_x][hold.s_y]) {
    isvisit[hold.s_x][hold.s_y] = true;
    if (hold.ismeet()) {
    cout << hold.step << endl;
    return;
    } else {
    vv.push(hold);
    }
    }
    }
    }
    }
    cout <<'-1' <<endl;
    }
     
    

      

  • 相关阅读:
    我用Python爬虫挣钱的那点事
    猿人学 . 爬虫逆向高阶课
    Python中实用却不常见的小技巧
    Python内存数据序列化到硬盘上哪家强
    利用setuptools发布Python程序到PyPI,为Python添砖加瓦
    配置tmux在机器重启后自动恢复tmux工作现场,告别重启恐惧症
    用python实现新词发现程序——基于凝固度和自由度
    学习笔记:Python序列化常用工具及性能对比
    浅谈自然语言在科技时代的运用
    python学习笔记:建立一个自己的搜索引擎
  • 原文地址:https://www.cnblogs.com/eggplant-is-me/p/6720058.html
Copyright © 2020-2023  润新知