题解 P1434 【滑雪】

曦行夜落

2018-01-02 19:52:34

Solution

这一题,看上去像是DP,但经过分析+标签,确定使用 ###记忆化搜索 首先来分析一般搜索的情况,最坏情况(样例),每个点都要搜到,枚举每个点O(n²),搜O(nlogn)不止,合起来就是O(n³logn)还不止,虽然能过,但是这**显然**不是最好的 首先讲一下算法: 1.由于不晓得从何处开滑,所以要以每个点为源搜一遍 2.每次搜索,都枚举周围4个点,如果可以去,就搜索那个点,具体实现: ```cpp int tmp=0; if (a[x][y]>a[x-1][y]) tmp=max(tmp,dfs(x-1,y)+1); if (a[x][y]>a[x+1][y]) tmp=max(tmp,dfs(x+1,y)+1); if (a[x][y]>a[x][y-1]) tmp=max(tmp,dfs(x,y-1)+1); if (a[x][y]>a[x][y+1]) tmp=max(tmp,dfs(x,y+1)+1); return tmp; ------>严肃,此时我们会发现,当调用dfs(2,1)和dfs(1,2)时,都会搜索dfs(1,1),完全是浪费,因为此时1,1的解可能已经求出 ``` 而我们用f[1][1]保存好1,1的解,就可以避免冗余,这也就是记忆化搜索 f数组初始化为0,如果已经搜过,f数组保存该点最优解,当调用dfs(x,y)时,先检查f[x][y],若不为0,则可以直接返回f值,否则再进行计算,计算完毕后,将结果保存至f数组,就可以在下一次运算中直接调用 记忆化搜索代码如下 ```cpp #define maxn 100+5 #include<iostream> #include<algorithm> #include<cstring> using namespace std; int r,c; int f[maxn][maxn],a[maxn][maxn]; int dfs(int x,int y) { if (x>0 && x<=r && y>0 && y<=c) return 1; if (f[x][y]) return f[x][y]; int tmp=0; if (a[x][y]>a[x-1][y]) tmp=max(tmp,dfs(x-1,y)+1); if (a[x][y]>a[x+1][y]) tmp=max(tmp,dfs(x+1,y)+1); if (a[x][y]>a[x][y-1]) tmp=max(tmp,dfs(x,y-1)+1); if (a[x][y]>a[x][y+1]) tmp=max(tmp,dfs(x,y+1)+1); f[x][y]=tmp; return f[x][y]; } int main() { cin >> r >> c; for (int i=1;i<=r;++i) for (int j=1;j<=c;++j) cin >> a[i][j]; for (int i=1;i<=r;++i) for (int j=1;j<=c;++j) f[i][j]=0; int ans=0; for (int i=1;i<=r;++i) for (int j=1;j<=c;++j) { f[i][j]=dfs(i,j); ans=max(ans,f[i][j]); } // for (int i=1;i<=r;++i,cout << endl) // for (int j=1;j<=c;++j) // cout << f[i][j] << " "; cout << ans; return 0; } ``` DP也非不可(juruo只是想过) 用dp[i,j]表示滑到i,j的最长路,可以为此dp4遍,一遍向右,一遍向左,一遍向上,一遍向下,然后取最大值即可 今年pj第三题,本人小学,写了半天DFS,还TLE,后来才发现那题可以DP,类似这题 喵,就是这样