1088:滑雪,考点:动态规划,或者排序
原题:http://bailian.openjudge.cn/practice/1088/
描述
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更长。事实上,这是最长的一条。
输入
输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。
输出
输出最长区域的长度。
样例输入
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
样例输出
25
解法
思路:动态规划,记忆性递归
dp[x][y]表示从x、y点开始滑的最长长度。每个点都要算,用表记录算出来的结果。复杂度应该是O(RC)。
代码如下:
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 int dp[105][105] = {}; 6 int num[105][105] = {}; 7 int R, C; 8 int jump(int x, int y) { 9 if (x < 0 || x >= R || y < 0 || y >= C) 10 return 0; 11 if (dp[x][y] != -1) 12 return dp[x][y]; 13 dp[x][y] = 1; 14 if (x - 1 >= 0 && num[x][y] > num[x - 1][y]) 15 dp[x][y] = max(jump(x - 1, y) + 1, dp[x][y]); 16 if (x + 1 < R && num[x][y] > num[x + 1][y]) 17 dp[x][y] = max(jump(x + 1, y) + 1, dp[x][y]); 18 if (y - 1 >= 0 && num[x][y] > num[x][y - 1]) 19 dp[x][y] = max(jump(x, y - 1) + 1, dp[x][y]); 20 if (y + 1 < C&&num[x][y] > num[x][y + 1]) 21 dp[x][y] = max(jump(x, y + 1) + 1, dp[x][y]); 22 return dp[x][y]; 23 } 24 int main() 25 { 26 cin >> R >> C; 27 for (int i = 0; i < R; i++) 28 for (int j = 0; j < C; j++) 29 cin >> num[i][j]; 30 memset(dp, -1, sizeof(dp)); 31 int maxlen = 0; 32 for(int i=0;i<R;i++) 33 for (int j = 0; j < C; j++) { 34 if (dp[i][j] == -1) 35 dp[i][j] = jump(i, j); 36 if (dp[i][j] > maxlen) 37 maxlen = dp[i][j]; 38 } 39 cout << maxlen << endl; 40 return 0; 41 }
如果是大于等于就可以向下滑,那么这道题要更复杂一点,记录轨迹,考察是否已经滑过了。(下面这个代码应该就可以,记录一下这种解法)
注:把下面这个代码交上去是不对的,因为这是大于等于就算在里面。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 int dp[105][105] = {}; 6 int num[105][105] = {}; 7 int R, C; 8 class point { 9 public: 10 int x, y; 11 point* pre; 12 point(int inx,int iny,point*p):x(inx),y(iny),pre(p){ 13 } 14 bool check(int tx, int ty) { 15 point* temp = pre; 16 while (temp != NULL) { 17 if (temp->x == tx && temp->y == ty) 18 return false; 19 temp = temp->pre; 20 } 21 return true; 22 } 23 }; 24 int jump(point nows) { 25 if (dp[nows.x][nows.y] != -1) 26 return dp[nows.x][nows.y]; 27 dp[nows.x][nows.y] = 1; 28 int x = nows.x; 29 int y = nows.y; 30 if (x - 1 >= 0 && num[x][y] >= num[x - 1][y]&&nows.check(x-1,y)) 31 dp[x][y] = max(jump(point(x - 1, y,&nows)) + 1, dp[x][y]); 32 if (x + 1 < R && num[x][y] >= num[x + 1][y]&&nows.check(x+1,y)) 33 dp[x][y] = max(jump(point(x + 1, y,&nows)) + 1, dp[x][y]); 34 if (y - 1 >= 0 && num[x][y] >= num[x][y - 1]&&nows.check(x,y-1)) 35 dp[x][y] = max(jump(point(x, y - 1,&nows)) + 1, dp[x][y]); 36 if (y + 1 < C&&num[x][y] >= num[x][y + 1]&&nows.check(x,y+1)) 37 dp[x][y] = max(jump(point(x, y + 1,&nows)) + 1, dp[x][y]); 38 return dp[x][y]; 39 } 40 int main() 41 { 42 cin >> R >> C; 43 for (int i = 0; i < R; i++) 44 for (int j = 0; j < C; j++) 45 cin >> num[i][j]; 46 memset(dp, -1, sizeof(dp)); 47 int maxlen = 0; 48 for(int i=0;i<R;i++) 49 for (int j = 0; j < C; j++) { 50 if (dp[i][j] == -1) 51 dp[i][j] = jump(point(i,j,NULL)); 52 if (dp[i][j] > maxlen) 53 maxlen = dp[i][j]; 54 } 55 cout << maxlen << endl; 56 return 0; 57 }
老师的排序解法:这是我为人人式递推,所有点按高度从小到大排序,从小到大遍历,经过一个点时更新周围比它高的点的值。
#include <iostream> #include <set> using namespace std; struct point { int x; int y; int height; point(int a,int b,int c):x(a),y(b),height(c){} bool operator<(const point &a)const { return height < a.height; } }; multiset<point>mountain; int heights[105][105]; int length[105][105]; int R, C; int dx[4] = { 1,-1,0,0 }; int dy[4] = { 0,0,1,-1 }; int main() { cin >> R >> C; int maxs = 1; for(int i=0;i<R;i++) for (int j = 0; j < C; j++) { cin >> heights[i][j]; mountain.insert(point(i, j, heights[i][j])); length[i][j] = 1; } multiset<point>::iterator i; for (i = mountain.begin(); i != mountain.end(); i++) { int nx = i->x; int ny = i->y; int nh = i->height; for (int k = 0; k < 4; ++k) { int tx = nx + dx[k]; int ty = ny + dy[k]; int th = heights[tx][ty]; if (tx >= 0 && tx < R&&ty >= 0 && ty < C) { if (th<nh&&length[tx][ty] + 1>length[nx][ny]) { length[nx][ny] = length[tx][ty] + 1; if (length[nx][ny] > maxs)maxs = length[nx][ny]; } } } } cout << maxs << endl; return 0; }