1 问题
(郭炜《算法基础与在线实践》7.6)
1.1 问题描述
小黑喜欢滑雪,为了能滑动,必须由高位置向低位置滑动,小黑想尽可能滑雪距离长。
有一个二维数组,代表每个地点的高程。
1.2 输入数据
第一行代表区域的行数R和列数C(1 <= R,C <= 100)。下面有R行,每行有C个整数,代表高度h,0 <= h <= 10000。
输出要求,输出最长滑行区域的长度。
1.3 输入示例
5 5 //代表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
1.4 输出示例
25
2 问题分析
设从某点开始,最长滑雪距离为L[i][j],i和j代表对应的行数和列数。对于任意位置i j 点,其L[i][j]等于上下左右最长滑雪距离+1(若周围有比它更低的点)。当某一点高度为全区域最低时,则无法滑动,对应的L为1。所以要先更新最低点的滑雪长度,由低点向高点进行遍历,直至遍历完所有区域点。“人人为我”型,周围的点都为当前点服务。
3 代码编写
#include <iostream>
#include <algorithm>
using namespace std;
struct Point{
int r,c; //当前的行号和列号
int h; //当前点的高度
};
int cmp(Point a,Point b){
return a.h < b.h; //可以按照升序排列
}
void test(){
int R,C;
cin >> R >> C;
Point* points = new Point[R*C]; //所有点信息
int** heights = new int*[R]; //高度信息
int** L = new int*[R]; //最长滑雪距离
for(int i = 0;i < R;i++){ //从第0行开始
heights[i] = new int[C];
L[i] = new int[C];
}
for(int i = 0;i < R;i++){
for(int j = 0;j < C;j++){
cin >> heights[i][j];
points[i*C+j].r = i; //行号
points[i*C+j].c = j; //列号
points[i*C+j].h = heights[i][j];
L[i][j] = 1; //将所有的滑雪距离都初始化为1
}
}
sort(points,points+R*C,cmp);
for(int i = 1;i < R*C;i++){ //从1开始,第0个L肯定为1
int r = points[i].r; //获取行号
int c = points[i].c; //获取列号
int h = heights[r][c];
if(r > 0 && heights[r-1][c] < h) //上面点更低
L[r][c] = max(L[r][c],L[r-1][c]+1);
if(r < R-1 && heights[r+1][c] < h) //下面更低
L[r][c] = max(L[r][c],L[r+1][c]+1);
if(c > 0 && heights[r][c-1] < h) //左边更低
L[r][c] = max(L[r][c],L[r][c-1]+1);
if(c < C-1 && heights[r][c+1] < h) //右边更低
L[r][c] = max(L[r][c],L[r][c+1]+1);
}
int maxlen = 0;
for(int i = 0;i < R;i++){
for(int j = 0;j < C;j++){
if(maxlen < L[i][j])
maxlen = L[i][j];
}
}
cout<<maxlen<<endl;
delete[] points;
delete[] heights;
delete[] L;
}
int main()
{
test();
return 0;
}