1088:滑雪,考點:動態規劃,或者排序
阿新 • • 發佈:2021-07-10
原題: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; }