洛谷P1434滑雪-题解
原题:
思路:
首先考虑暴搜。
对于每一个点,我记录到这一格为止,走过了多少路。然后枚举四个方向继续递归。直到彻底走不动之后,就停下来更新答案。
但是有个问题——数据规模最大100行100列,如果我以一次递归4个方向来计算,第一层4种,第二层16种,第三层64种,第四层256种,而假设我们从整个地图的中间开始找,至少要花50步找到边界,而此时共有450种方案,这个数是1,267,650,600,228,229,401,496,703,205,376
这个数肯定爆炸
所以我们想到那些我们常用的优化。
第一,剪枝。
对于每一个到达的点,我们开一个数组记忆到这个点的最长步数。
如果最长步数大于这次到达这个点时的步数,我们可以不继续。
第二,记忆化搜索。
仍然记忆最长步数,如果这个点之前走过直接返回这个值。
对于每一个点的记忆值,我们选四个方向的返回值中最大的那个+1
由这个,我们想到了DP。
DP思路与上述记忆化搜索差不多废话记忆化搜索就是DP,详见下附代码
代码:
DP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #include<bits/stdc++.h> using namespace std; int n,m,maxn; int mp[105][105]; int f[105][105]; struct node { int x; int y; int w; }N[10005]; int cnt; bool cmp( struct node a, struct node b) { return a.w<b.w; } int main() { cin >> n >> m; for ( int i=1;i<=n;i++) for ( int j=1;j<=m;j++) { cnt++; cin >> mp[i][j]; N[cnt].x=i; N[cnt].y=j; N[cnt].w=mp[i][j]; f[i][j]=1; } sort(N+1,N+1+cnt,cmp); for ( int i=1;i<=cnt;i++) { int x=N[i].x; int y=N[i].y; int w=N[i].w; if (w>mp[x-1][y]) f[x][y]=max(f[x][y],f[x-1][y]+1); if (w>mp[x][y-1]) f[x][y]=max(f[x][y],f[x][y-1]+1); if (w>mp[x+1][y]) f[x][y]=max(f[x][y],f[x+1][y]+1); if (w>mp[x][y+1]) f[x][y]=max(f[x][y],f[x][y+1]+1); if (maxn<f[x][y]) maxn=f[x][y]; } cout << maxn << endl; return 0; } |
剪枝(这个写法有一个点超时,吸了氧过的,或许有更好写法):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | #include <bits/stdc++.h> using namespace std; int n,m; int sx,sy; int cnt; int mp[150][150]; int f[150][150]; bool bk[150][150]; bool vis[150][150]; int tmp; int ans; int nxt[4][2]={{0,1},{1,0},{0,-1},{-1,0}}; struct node { int x,y,height; }N[10050]; bool cmp( struct node a, struct node b) { return a.height>b.height; } void dfs( int x, int y, int stp) { bk[x][y]= false ; cnt++; if (f[x][y]>stp) return ; f[x][y]=stp; for ( int i=0;i<4;i++) { int tx=x+nxt[i][0]; int ty=y+nxt[i][1]; if (tx<=0||tx>n||ty<=0||ty>m) continue ; if (mp[tx][ty]<mp[x][y]&&!vis[tx][ty]) { vis[tx][ty]= true ; dfs(tx,ty,stp+1); vis[tx][ty]= false ; } } if (stp>ans) ans=stp; } int main() { cin >> n >> m; for ( int i=1;i<=n;i++) for ( int j=1;j<=m;j++) cin >> mp[i][j]; //下面的循环是重点 //如果只从最高点开始搜索 //一旦遇到 /*0 94 93 92 0 96 95 98 91 90 97 98 0 98 89 98 0 99 0 98*/ //就会被卡 //其原因在于 //从最高点开始搜索,则搜索轨迹是 /* ***** ***** **#** *###* */ //就这么结束了 //显然不能覆盖所有点 //就无法得出正确答案 for ( int i=1;i<=n;i++) for ( int j=1;j<=m;j++) if (!bk[i][j]) { f[i][j]=1; dfs(i,j,1); } cout << ans; return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2015-08-07 VC++ 标准C++中的string类的用法总结
2011-08-07 删除文件夹及文件的操作方法(记下,以备后用)