【Memory Search】| AcWing 901. Skiing

901. Skiing

Title description

Given a matrix with R rows and C columns , it represents a rectangular grid ski resort.
The point in the i-th row and j-th column of the matrix represents the height of the area in the i-th row and j-th column of the ski resort.
A person starting from a certain area in the ski resort can slide a unit distance in either direction up, down, left, or right.
Of course, an individual is able to slide into a neighboring region is a prerequisite for the height of the area below the height of the area of their current location .
Here is a matrix as an example:

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

In a given matrix, a feasible taxi trajectory is 24-17-2-1.
In a given matrix, the longest taxi trajectory is 25-24-23-...-3-2-1, passing through 25 areas along the way.
Now given you a two-dimensional matrix representing the height of each area of the ski resort , please find out the longest ski track that can be completed in the ski resort , and output its length (the maximum number of areas that can be passed through).

Input format

The first line contains two integers R and C.
The next R rows, each row contains C integers, representing a complete two-dimensional matrix.

Output format
Output an integer, indicating the longest ski length that can be completed.

Data range
1≤R, C≤300,
0≤integer in matrix≤10000

Input sample:

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

Sample output:

25

analysis

Deep search, each position can slide in up to 4 directions, so it can be regarded as a tree with up to 4 branches. To find the recursive length from a certain point is to find the maximum tree height with a certain point as the root:

Assuming that it starts to slide down from a certain point (x, y), it can go in four directions to determine whether its next position is legal:

  1. Whether the next position is a wall
  2. Is the height of the next position strictly lower than the current position

Once the conditions are met, one recursion can be performed, and each recursion is to slide in one direction once, and the slide length is +1.
Recursion is no longer nested recursion but the condition for going back up is that it encounters a leaf node. When all reachable points are recursive, the recursion ends once, and the largest tree height is taken as the current farthest sliding distance.

Therefore, each starting point can get a maximum sliding distance. There are n×m starting points. After n×m deep searches, the maximum sliding distance of a certain time can be taken.

The time complexity is high.

Code

#include <iostream>
#include <cstring>
#define read(x) scanf("%d",&x)

using namespace std;

const int N=310;
int h[N][N];
int dx[4]={
    
    0,0,-1,1},dy[4]={
    
    1,-1,0,0};//表示上下左右四个方向
int n,m,res=0;//n行m列

void dfs(int x,int y,int len)
{
    
    
    if (len>res) res=len;
    for (int i=0;i<4;i++) {
    
    
        int a=x+dx[i],b=y+dy[i];
        if (a>=1 && a<=n && b>=1 && b<=m && h[a][b]<h[x][y]) dfs(a,b,len+1);
    }
}

int main()
{
    
    
    read(n),read(m);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++) read(h[i][j]); //从下标1开始存储数据,下标0代表墙不可达
    
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)  dfs(i,j,1); "初始长度为1"
        
        
    printf("%d",res);
    
    return 0;
}

According to the recursive writing, the position entered is guaranteed to be legal each time, so the length can be accumulated before recursion.
When searching from the starting point, the starting point is already a point in the length, so the length starts from 1.

Memory search

It is still a deep search, but maintain a memory array dp , record the maximum sliding length from each point , detect the points in the four directions of the point, if you can slide to other points, in the
dp[i][j] = max(dp[i][j-1], dp[i][j+1],dp[i-1][j],dp[i+1][j])four directions up , down, left , and right

The value of the dp two-dimensional array after the final processing must be greater than or equal to 1, so it is initialized to -1 when initializing. When it is -1, it means that it has not been processed and needs to be processed, otherwise it is processed, and the value is used directly That's it.

#include <iostream>
#include <cstring>
#define read(x) scanf("%d",&x)

using namespace std;

const int N=310;
int h[N][N],f[N][N];
int dx[4]={
    
    0,0,-1,1},dy[4]={
    
    1,-1,0,0};//表示上下左右四个方向
int n,m;//n行m列

int dp(int x,int y)
{
    
    "保证进来的坐标(x,y)是合法的"
    int &v=f[x][y];   v等价于f[x][y],共用同一块内存
    if (v!=-1) return v;       "说明v开始往下滑的情况已经计算过了,直接返回就行。"
    v=1; 初始化为1"否则,把当前点当作起点,v的值初始化为1,向四个方向滑"
    for (int i=0;i<4;i++) {
    
    
        int a=x+dx[i],b=y+dy[i];
  "判断(a,b)是否合法"
        if (a>=1 && a<=n && b>=1 && b<=m && h[a][b]<h[x][y]) 
            v=max(v,dp(a,b)+1);  "这里还要给v赋值,时刻更新,保证v的值是最大的"
    }
    return v;
}

int main()
{
    
    
    read(n),read(m);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++) read(h[i][j]); //从下标1开始存储数据,下标0代表墙不可达
    memset(f,-1,sizeof f);      "给数组f初始化为-1,f[i][j]==-1时表示该点还未进行处理"
  把每个点都作为一次滑雪起点,挨个遍历
  当前起点是肯定可以开始的,至于能不能往其它四个方向滑取决于周围的高度是不是比它低
  所以起点处的长度肯定要算上,即f数组的最小值就为1,初始化res为0
    int res=0;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++) res=max(res,dp(i,j));
        
    printf("%d",res);
    
    return 0;
}

Similar to the processing routine of union search , when using dp[i][j]the value, if it is not solved, it will be solved recursively and then used, if it has already been solved, it can be used directly.

However, when starting to search down from the point (i, j) as the node, since the 4 directions will be updated up to 4 times dp[i][j]to find dp[i][j]the maximum value, the calculated dp[i][j]value may change. The maximum value is also determined by its subtree, so it must be written v=max(v,dp(a,b)+1);and the return result assignment must be obtained. When dp[i][j]the value is calculated , he is fixed.

2021.03.13 More
recently, I have been obsessed with memorizing search when doing questions, but I found that nothing is right, thinking about where the problem occurred.

  1. Before d[i][j]the value of before is recorded, it will not be used directly by any point that needs it;

  2. After a bit of sliding to (i, j),
     if d[i][j]the value is not recorded, then a deep search will be made to find dfs(i,j)the maximum length of sliding from (i, j) d[i][j]. In the deep search process, up to four directions will be involved Update, get the maximum length, d[i][j]the value afterwards will not change;
     if d[i][j]the value has been recorded, then it is directly used, no longer recursive.

  3. Once dfs(i,j)the maximum length d[i][j]of sliding from (i, j) is obtained through a deep search , d[i][j]the value will not change. After that, d[i][j]the value can be used directly by any point that needs it.

In this problem, there is more than one starting point. In the main function, dfs(1,1)the maximum ski length starting from (1,1) can be obtained. At the same time, the maximum ski length of all points reachable from (1,1) will also be updated . The maximum ski length has also been fixed and cannot be changed.

If (1,1) is the starting point and (1,1)->(1,2) is reachable, the calculation d[1,1]will inevitably require data d[1,2], so d[1,2]it is also fixed, because if you then calculate (1,2) as the starting point to find d[ In the case of 1,2], his way of thinking is the same as when calculating d[1,1] to find d[1,2], and it is impossible for him to go through (1,1), the path is not descending, so he has actually calculated it just now Up.

Therefore, the calculation completed d[1,1]after from (1,1) to start up all the points (i, j) the d[i,j]have been calculated, because a multi-start , n * n points can be a starting point to do so will continue to calculate other In the case of a vertex, if it is a reachable point, it has been calculated before and it can be returned directly. If it has not been calculated, that is, there is still an unreachable point, then recursion is sufficient.

It can be seen that when seeking a point d[i][j], there are up to 4 directions, and d[i][j]the value will be updated . After the maximum value is found at a point, its value will remain unchanged for future generations to use. In addition, when seeking dp[i][j], all its sub- The d value of the node will be calculated.

Conditions for using memoized search:

After recursively finding the attribute value of a point, it will be used in the future. If some deep search process only traverses each point once, and the recursive search is over once, there is no need to consider memory search, consider pruning optimization .

Guess you like

Origin blog.csdn.net/HangHug_L/article/details/114539670