[SHOI2002] 滑雪(记忆化搜索)
该题思路上很容易想到使用搜索进行解决,只需遍历每一个点作为起点进行搜索,对能够到达的最远距离进行计算,最后对每一个搜索得到的距离取最大值即可 #include<iostream> #include<climits> #include<cmath> #include<cstring> using namespace std; const int MAX=105; int r,c,ans=INT_MIN; int mapp[MAX][MAX]; int nextt[4][2]={ {0,1},{1,0},{0,-1},{-1,0}}; bool check(int x,int y){ for(int i=0;i<4;i++){ int tx=x+nextt[i][0]; int ty=y+nextt[i][1]; if(tx>=1&&ty>=1&&tx<=r&&ty<=c&&mapp[tx][ty]<mapp[x][y]){ return false; } } return true; } void dfs(int x,int y,int len){ if(check(x,y)){//滑不动了 ans=max(len,ans); }else{ for(int i=0;i<4;i++){ int tx=x+nextt[i][0]; int ty=y+nextt[i][1]; if(tx>=1&&ty>=1&&tx<=r&&ty<=c&&mapp[tx][ty]<mapp[x][y]){ dfs(tx,ty,len+1); } } } } int main() { cin>>r>>c; for(int i=1;i<=r;i++){ for(int j=1;j<=c;j++){ cin>>mapp[i][j]; } } for(int i=1;i<=r;i++){ for(int j=1;j<=c;j++){ dfs(i,j,1); } } cout<<ans<<endl; return 0; } 但是这样的方法实际上还可以进行一些有效的优化
这里我们尝试使用记忆化搜索 因为普通搜索时,我们有时可能会用到之前所搜索到的结果,这时如果我们再次搜索就显得没有必要了(会浪费很多时间呢),所以如果我们已经记录了之前搜索的答案不就可以直接用之前的搜索答案了么 因此我们使用一个数组来存储每一个点所能到达的最远距离,从而实现记忆化 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 200;//数据并不大 const int dx[]={0,0,1,-1}; const int dy[]={1,-1,0,0}; int r,c,ans; int map[maxn][maxn],step[maxn][maxn]; int dfs(int x,int y){ if(step[x][y]) return step[x][y];//一开始每个点的步数都应为0;如果当前这个点已知其最大步数说明之前该点已被计算过就不用再重复计算了 step[x][y]=1;//既然这是一个从未走过的点那么现在来到该点至少都会使其步数为1 for(int i=0;i<4;i++){//四个可行的方向 int nx=x+dx[i],ny=y+dy[i]; if(map[nx][ny]<map[x][y]){ step[x][y]=max(step[x][y],1+dfs(nx,ny));//代码核心 } } return step[x][y];//返回值给上一个dfs调用 } int main(){ ios::sync_with_stdio(false); scanf("%d%d",&r,&c); //初始化处理 for(int i=0;i<=c+1;i++){//将边界的高度设为无限高这样就免去了判断是否超出地图限制 map[i][0]=map[i][c+1]=1e9; } for(int i=0;i<=r+1;i++){ map[0][i]=map[r+1][i]=1e9; } //读入每个点的数据 for(int i=1;i<=r;i++){ for(int j=1;j<=c;j++){ scanf("%d",&map[i][j]); } } for(int i=1;i<=r;i++) for(int j=1;j<=c;j++) ans=max(dfs(i,j),ans);//每一个点都跑一边dfs,答案取最大的就是题目要求了 printf("%d",ans); return 0; }
