POJ 1088.滑雪
Description
Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道载一个区域中最长底滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子
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
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。
Input
输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。
Output
输出最长区域的长度。
Sample Input
5 5
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
从i,j出发,最长的一条道路就是上下左右四个方向最多的道路数+1,如果四周的点都比当前的点高,那么这个点的道路数就是1,递推的话不好实现,因为四周点的道路数是不知道的,所以可以用记忆化搜索
#include<vector>
#include<iostream>
#define rep(i,a,b) for(int i=(a); i<(int)(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(int)(b);++i)
using namespace std;
int n,m,nums[105][105];
vector<vector<int>> dp;
int infer(int r,int c)
{
if(dp[r][c]>0) return dp[r][c];
dp[r][c]=1;
if(r-1>=0&&nums[r-1][c]<nums[r][c])
dp[r][c]=max(dp[r][c],infer(r-1,c)+1);
if(r+1<n&&nums[r+1][c]<nums[r][c])
dp[r][c]=max(dp[r][c],infer(r+1,c)+1);
if(c-1>=0&&nums[r][c-1]<nums[r][c])
dp[r][c]=max(dp[r][c],infer(r,c-1)+1);
if(c+1<m&&nums[r][c+1]<nums[r][c])
dp[r][c]=max(dp[r][c],infer(r,c+1)+1);
return dp[r][c];
}
int main()
{
cin>>n>>m;
rep(i,0,n)
rep(j,0,m)
cin>>nums[i][j];
dp.assign(n,vector<int>(m,-1));
int maxn=0;
rep(i,0,n)
rep(j,0,m)
maxn=max(maxn,infer(i,j));
cout<<maxn;
return 0;
}
之所以递推不好实现就是因为四周点的道路数不知道
分析后会发现,只有该点四周的点高度比较低才能够进行计算,所以我们可以事先把所有的点从低到高排序,计算时也从低到高,这样相邻点的道路数是肯定知道的
保存的时候可以保存到,一个一维数组中,方便排序,不过注意是R个一组还是C个一组
人人为我型动态规划
通过已知的的状态的值,推算未知状态的值
#include<iostream>
#include<algorithm>
#define rep(i,a,b) for(int i=(a); i<(int)(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(int)(b);++i)
using namespace std;
static const auto io_sync_off = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
return nullptr;
}();
struct point
{
int r,c,h;
bool operator < (const point &rhs)const
{
return h<rhs.h;
}
}point[10005];
int dp[105][105];
int nums[105][105];
int main()
{
int n,m;
cin>>n>>m;
rep(i,0,n)
rep(j,0,m)
{
cin>>nums[i][j];
point[i*m+j].r=i; //注意是i*m,m个一组
point[i*m+j].c=j;
point[i*m+j].h=nums[i][j];
dp[i][j]=1;
}
sort(point,point+n*m);
rep(i,0,n*m)
{
int r=point[i].r;
int c=point[i].c;
if(r>0&&nums[r-1][c]<nums[r][c])
dp[r][c]=max(dp[r][c],dp[r-1][c]+1);
if(r+1<n&&nums[r+1][c]<nums[r][c])
dp[r][c]=max(dp[r][c],dp[r+1][c]+1);
if(c>0&&nums[r][c-1]<nums[r][c])
dp[r][c]=max(dp[r][c],dp[r][c-1]+1);
if(c+1<m&&nums[r][c+1]<nums[r][c])
dp[r][c]=max(dp[r][c],dp[r][c+1]+1);
}
int ans=0;
rep(i,0,n)
rep(j,0,m)
ans=max(ans,dp[i][j]);
cout<<ans;
return 0;
}
我为人人型动态规划
x点状态已知,可以推算出受x点影响的点的状态
rep(i,0,n*m)
{
int r=point[i].r;
int c=point[i].c;
if(r>0&&nums[r-1][c]>nums[r][c])
dp[r-1][c]=max(dp[r-1][c],dp[r][c]+1);
if(r+1<n&&nums[r+1][c]>nums[r][c])
dp[r+1][c]=max(dp[r+1][c],dp[r][c]+1);
if(c>0&&nums[r][c-1]>nums[r][c])
dp[r][c-1]=max(dp[r][c-1],dp[r][c]+1);
if(c+1<m&&nums[r][c+1]>nums[r][c])
dp[r][c+1]=max(dp[r][c+1],dp[r][c]+1);
}