洛谷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:
#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;
}
剪枝(这个写法有一个点超时,吸了氧过的,或许有更好写法):
#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;
}
浙公网安备 33010602011771号