空间转换成时间——“改写的广搜”完成深搜(全遍历情况)

来源:互联网 发布:windows自带编译器 编辑:程序博客网 时间:2024/06/06 17:30

前言
想必大家以前都是用过广搜替换深搜的做法。这里的这道题,也是有类似的处理,只不过却有很大的变化。下面用SOJ1321 Robot来举例子
如果不习惯看英语的话,就直接跳到后面的解析吧
题目
Description
Karell Incorporated has designed a new exploration robot that has the ability to explore new terrains, this new robot can move in all kinds of terrain, it only needs more fuel to move in rough terrains, and less fuel in plain terrains. The only problem this robot has is that it can only move orthogonally, the robot can only move to the grids that are at the North, East, South or West of its position.

The Karell`s robot can communicate to a satellite dish to have a picture of the terrain that is going to explore, so it can select the best route to the ending point, The robot always choose the path that needs the minimum fuel to complete its exploration, however the scientist that are experimenting with the robot, need a program that computes the path that would need the minimum amount of fuel. The maximum amount of fuel that the robot can handle is 9999 units

The Terrain that the robot receives from the satellite is divided into a grid, where each cell of the grid is assigned to the amount of fuel the robot would need to pass thought that cell. The robot also receives the starting and ending coordinates of the exploration area.

这里写图片描述
Path Example
From (1,1) to (5,5)
Fuel needed 10
Input
The first line of the input file is the number of tests that must be examined.

The first line of the test is the number of rows and columns that the grid will contain. The rows and columns will be 0 < row100 , 0 < column100

The next lines are the data of the terrain grid

The last line of the test has the starting and ending coordinates.

Output
One line, for each test will have the amount of fuel needed by the robot

Sample Input
Copy sample input to clipboard
3
5 5
1 1 5 3 2
4 1 4 2 6
3 1 1 3 3
5 2 3 1 2
2 1 1 1 1
1 1 5 5
5 4
2 2 15 1
5 1 15 1
5 3 10 1
5 2 1 1
8 13 2 15
1 1 1 4
10 10
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 10 10

Sample Output
10
15
19

解析 解析在这里!!!!!!!!!!!!!!!!
上面就是给了一个图,在每个图上就要消耗一定的能源(对应的数值)。然后给出起始点的横纵坐标,和终点的横纵坐标
让我们算一下,最短的路径有多长。
要注意的是,这里的小机器人,只能上下左右移动,且每次只能移动一格

解题思路:
一开始,考虑到这个每一个点的消耗不是一个固定的数(就是不是等值的),那么就不太好用广搜(广搜一般所搜到最短路径,其实在逻辑结构上的最短层次,即最小步数 )。
然后,再看最多规模是100*100,那么点的数量是可以达到10000,那用Dijkstra算法虽然也是可以做的,但很明显也不是那么合适的。
所以,一开始我用的是深搜(DFS)

#include <iostream>#include <cstring>#include <stack> using namespace std;int map[100][100];int bx,by,ex,ey;int ox[4] = {1,-1,0,0};int oy[4] = {0,0,1,-1};bool visited[100][100];int ans, n, m;;void DFS(int x,int y,int p) {    if(visited[x][y])        return;    visited[x][y] = true;    if (x == ex&& y == ey && ans > p)         ans = p;    int tx,ty;    for (int i = 0;i<4;++i) {        tx = x + ox[i];        ty = y + oy[i];        if (tx < 0 || ty < 0 || tx >= m || ty >= n || p+map[tx][ty] >= ans)             continue;        DFS(tx,ty,p+map[tx][ty]);    }    visited[x][y] = false;}int main(){    int time;    cin >> time;    while (time--){         cin>> n>> m;         for (int i = 0;i < n;++i) {            for (int j = 0; j < m; ++j) {                cin >> map[i][j];             }        }         memset(visited,false,sizeof(visited));        cin >> bx>> by>> ex>> ey;        bx--; by--; ex--; ey--;        ans = 1<<30;        DFS(bx,by,map[bx][by]);        cout << ans<< endl;    }} 

然后,没想到这题还有点难,居然这样的结果不行(要注意,我在上面其实已经做了一个减枝的,但是居然还是不行,这就有点悬了….)
然后我就想,是不是可以把cin、cout那些换掉,然后还是失败了。
(快了0.01sec)没什么用….

那我就想转换成广搜,结果….也不知道该怎么搞,因为这个确实很难搞(又试了下动归,似乎也搞不出)。
后来看到网上的一个10年的一个师兄写的解答,收到启发。
他是用优先级对列来构造,这样构造出来的结果,就是,每一次都是选离起始点最近的点开始扩散,那么其实拿出来的那个点,都是用离起点最近的那个点开始扩散得到新的点,那么,每次都会是比较最近的那个点,如果这时遇到了终点,就必定是最近的那条路径。

这里,用到了一个条件,那就是和终点连接的点其实只有4个(最多)。就是看一直用最短的那个点进行选择,看最终能选中 哪一个节点。
配合上代码,可能会更清晰。
对了,当时我为了提高我算法的空间和时间,然后改的越来越接近师兄给的解答代码(在思路上 接近,并没有看着代码写),结果还是没有所改进……也不想改回去了,想着这也没什么好避嫌的,就直接放上来了。建议各位看官先理解好代码思路之后,再进行自主编写,这样效率高点
代码:

#include <iostream>using namespace std;#include <cstring>#include <queue>int map [100][100];int bx,by,ex,ey,n,m;int ox[4] = {1,-1,0,0};int oy[4] = {0,0,1,-1};bool visited[100][100];struct Node {    int x,y,cost;    Node(int xx=-1,int yy=-1,int cc=-1) {        x = xx; y = yy; cost = cc;     }     bool operator < (const Node& n)const{        return cost > n.cost;    }};int main(){    int time;    cin >> time;    while(time--) {        cin >> n >> m;        for (int i = 0; i < n; ++i) {            for (int j = 0; j < m;++j) {                cin >> map[i][j];            }        } // Read         cin >> bx>> by>> ex>> ey;        bx--; by--; ex--; ey--;        if (bx == ex && by == ey){            cout << map[bx][by]<< endl; continue;        }        memset(visited,false,sizeof(visited));        priority_queue<Node> q;        q.push(Node(bx,by,map[bx][by]));        visited[bx][by] = true;        while (!q.empty()) {            Node now = q.top();            q.pop();            int i;            for (i = 0; i < 4; ++i) {                bx = now.x + ox[i]; by = now.y + oy[i];                if (bx < 0 || by < 0|| bx >= n || by >= m || visited[bx][by])                     continue;                if (bx == ex && by == ey) {                    cout << now.cost + map[bx][by]<< endl;                    break;                }                q.push(Node(bx,by,now.cost + map[bx][by]));                visited[bx][by] = true;            }            if (i < 4) break;        }    }   }

最后,老套路,宣传一波自己的公众号!(求关注哇!)
本人中大一肥宅,欢迎大家关注,请扫下面的二维码(〃’▽’〃)


二维码

原创粉丝点击