Luogu P1434 滑雪

正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!左边有个“赞”字,你就顺手把它点了吧

题目描述

Michael喜欢滑雪。这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道在一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子:

1  2  3  4  5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9

一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可行的滑坡为24-17-16-1(从24开始,在1结束)。当然25-24-23 - … - 3 ― 2 ― 1更长。事实上,这是最长的一条。

输入输出格式

输入格式:

输入的第一行为表示区域的二维数组的行数R和列数C(1≤R,C≤100)。下面是R行,每行有C个数,代表高度(两个数字之间用1个空格间隔)。

输出格式:

输出区域中最长滑坡的长度。

输入输出样例

输入样例#1:
5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
输出样例#1:
25

典型bfs

评测记录 52ms / 2085KB

虽然本题数据很水,但是我们还是需要用BFS+记忆化,否则会TLE好几个点

先从样例入手。样例的解显然是从(3, 3)的25开始,按照红线的顺序,到(1, 1)的1,总长度为25。

题目要求最优解,所以我们必须把所有可能的情况都枚举出来!我们用变量ans来记录最优解。

我们将会枚举整个地图的每个点。当然,这是不可行的。因为如果你直接这样做,那么最坏情况时间复杂度将是O(nm*nm),显然会超时。所以,我们必须使用记忆化搜索,那么时间复杂度会降低为O(nm)。

我们用mp来存储整个地图,用f来存储每个点能滑的最大长度。由于要枚举每一个点的情况,那么我们使用双层循环。每次循环,我们用ans=max{ans + f[i][j]}求出到目前为止最长的长度。最后输出即可。


我们来看看整个程序的核心:void bfs(int x, int y)。这里用一个结构体POINT来表示地图上一个点的x轴与y轴,以及从起点(i, j)到当前点的距离n。这里为了方便起见,使用STL的单向队列。如果有兴趣的朋友还可以尝试手写队列。

当然,滑雪是不能滑到地图外面的!所以,我们应加上条件判断,若有以下任意一种情况则用continue跳过本次循环:pos.x<1pos.y<1pos.x>npos.y>m。这是边界判断。

然后,我们得判断当前这个点是否已经被搜过!这也是记忆化搜索的核心。由于在之前我们已经将f全部赋值为INF了,所以要判断是否被搜过,我们只需判断f[i][j]!=INF的情况,那样,我们就只需将搜过的数据f[i][j]拿来直接用就行了。在这把临时变量b赋值为true,由于已经搜过了,就不必再搜一次了,将f[i][j]赋值为当前最优解后,如果b为true,那么我们直接可以跳过本次循环,因为已经搜过了。

后面,四行代码,就是分别向上下左右扩展,向队列里push元素,下一次循环时遍历。这里的if就是条件判断:新的点的值是否小于当前点的值,因为根据牛顿万有引力定律,只能向下滑。


于是很愉快地AC了…

#include 
#include 
using namespace std;
#define max(a, b) (((a)>(b))?(a):(b))
#define INF -2147483648
struct POINT {
    int x;
    int y;
    int n;
};
int n, m;
int mp[110][110];
int f[110][110];
POINT point(int x, int y, int n) {
    POINT pos;
    pos.x = x;
    pos.y = y;
    pos.n = n;
    return pos;
}
void bfs(int x, int y) {
    queue  q;
    q.push(point(x, y, 1));
    while(!q.empty()) {
        POINT pos = q.front(); q.pop();
        if(pos.x < 1 || pos.y < 1 || pos.x > n || pos.y > m) continue;
        bool b = false;
        if(f[pos.x][pos.y] != INF) pos.n += f[pos.x][pos.y]-1, b = true;
        if(pos.n > f[x][y]) f[x][y] = pos.n;
        if(b == true) continue;
        if(mp[pos.x][pos.y] > mp[pos.x+1][pos.y]) q.push(point(pos.x+1, pos.y, pos.n+1));
        if(mp[pos.x][pos.y] > mp[pos.x][pos.y+1]) q.push(point(pos.x, pos.y+1, pos.n+1));
        if(mp[pos.x][pos.y] > mp[pos.x-1][pos.y]) q.push(point(pos.x-1, pos.y, pos.n+1));
        if(mp[pos.x][pos.y] > mp[pos.x][pos.y-1]) q.push(point(pos.x, pos.y-1, pos.n+1));
    }
}
int main() {
    int ans = 0;
    cin >> n >> m;
    for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) cin >> mp[i][j], f[i][j] = INF;
    for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) bfs(i, j), ans = max(ans, f[i][j]);
    cout << ans;
    return 0;
}

你可能感兴趣的:(搜索,搜索,-,广度优先搜索,搜索,-,记忆化搜索)