1. 程式人生 > >POJ1088 滑雪【動態規劃】

POJ1088 滑雪【動態規劃】

題目:

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
思路:

一開始我是以為,山峰肯定只有一個峰,那這樣的話,找到最高的那個點,在它周圍慢慢找高度減小的點就好了。後來發現我太naive了,下面就是其中一組測試資料。

12 13
1 1 30 4 800 6 7 8 99 10 1223 1
20 30 30 4 16 15 14 13 12 11 1
21 22 99 444444 88 9926 27 9928 9929 3000 456 1
40 39 1 90 36 35 34 33 3992 30001 789 1
41 42 4000 44 88 46 47 48 49 50 897 1
1 59 1 57 56 85 54 53 52 51 908 1
61 77 56 64 444 66 67 68 69 70 1234 1
80 79 78 77 76 75 74 73 72 71 12345 1
81 82 2 2 4 86 5 88 8 90 3456 1
100 99 98 97 96 95 94 93 92 91 567 1
890 654 623 154 683 15414 86549 633 123 456 123456 1
9517 45632 643164 3478643 43 16 431 64453132 689431 746546 15643 1
64543 13146543 13474 314789 4352154 65431 631 654324 65132 89547 34567312 1 1

答案是27

所以不能想得太簡單。正確的思路應該是這樣的:題意為,給出一個二維陣列,讓你求出最長遞減序列長度,可以四個方向行走,起點任意。要對於每個點,都算出到達1的最長路徑。

如果單純的遞迴,會超時,時間限制只有1000ms,所以加點小技巧,每次第一次訪問一個點,就記錄它到達1的最長路徑,當下次訪問時,就直接返回記錄的值。即用一個數組dis[101][101]儲存每個節點的最長路徑,先初始化為0,每當訪問一個節點時,就判斷dis值是否大於0,大於0則此點的值就是dis的值,直接返回。

程式碼:

#include<iostream>
using namespace std;
int map[101][101]={0};//存原始資料
int r,c;//行數,列數
int dis[101][101]={0};//儲存節點的最長路勁值

int f(int form,int to){
	if(dis[form][to]>0)return dis[form][to];//如果已經記錄了值,直接返回
	int zuo=0,you=0,shang=0,xia=0;
	if(form+1<=r){//處理上路
		if(map[form+1][to]<map[form][to])shang=1+f(form+1,to);
		else shang=1;
	}
	else shang=1;
	if(form-1>=1){//處理下路
		if(map[form-1][to]<map[form][to])xia=1+f(form-1,to);
		else xia=1;
	}
	else xia=1;
	if(to+1<=c){//處理右路
		if(map[form][to+1]<map[form][to])you=1+f(form,to+1);
		else you=1;
	}
	else you=1;
	if(to-1>=1){//處理左路
		if(map[form][to-1]<map[form][to])zuo=1+f(form,to-1);
		else zuo=1;
	}
	else zuo=1;
	if(zuo<you)zuo=you;
	if(zuo<shang)zuo=shang;
	if(zuo<xia)zuo=xia;
	return zuo;//返回最大值
}

int main(){
	int i,j;
	cin>>r>>c;
	for(i=1;i<=r;i++)
		for(j=1;j<=c;j++)
			cin>>map[i][j];
	int sun=0;
	for(i=1;i<=r;i++)
		for(j=1;j<=c;j++){
			dis[i][j]=f(i,j);//記錄每個節點的最長路勁
			if(sun<dis[i][j])sun=dis[i][j];//選出最大長度
		}
	cout<<sun<<endl;
	return 0;
}
/*
測試資料
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


1 1
1

1 2
1 2

1 3 
1 3 2

2 2
1 2 
4 3

2 2 
1 2 
3 4

4 7
7 6 5 4 3 2 1
1 5 1 1 1 1 1
1 4 3 1 1 1 1
1 5 6 7 8 1 1

3 3
9 1 2
5 6 7
8 4 3

3 4
1 2 3 4
8 7 6 5
9 10 11 12

3 3
0 0 0
0 5 0
0 0 0

12 13
1   1 30  4  800  6  7  8  99 10 1223 1
20 30 30 4 16 15 14 13 12 11 1
21 22 99 444444 88 9926 27 9928 9929 3000 456 1
40 39 1 90 36 35 34 33 3992 30001 789  1
41 42 4000 44  88 46 47 48 49 50 897  1
1 59 1 57 56  85 54 53 52 51 908 1
61 77 56 64 444 66 67 68 69 70 1234 1
80 79 78 77 76 75 74 73 72 71 12345 1
81 82 2  2 4 86 5 88 8 90 3456  1
100 99 98 97 96 95 94 93 92 91 567 1
890 654 623 154 683 15414 86549 633 123 456 123456  1
9517 45632 643164 3478643 43 16 431 64453132 689431 746546 15643 1
64543 13146543 13474 314789 4352154 65431 631 654324 65132 89547  34567312 1 1


13 12
1   1 30  4  800  6  7  8  99 10 1223 1
20 30 30 4 16 15 14 13 12 11 1
21 22 99 444444 88 9926 27 9928 9929 3000 456 1
40 39 1 90 36 35 34 33 3992 30001 789  1
41 42 4000 44  88 46 47 48 49 50 897  1
1 59 1 57 56  85 54 53 52 51 908 1
61 77 56 64 444 66 67 68 69 70 1234 1
80 79 78 77 76 75 74 73 72 71 12345 1
81 82 2  2 4 86 5 88 8 90 3456  1
100 99 98 97 96 95 94 93 92 91 567 1
890 654 623 154 683 15414 86549 633 123 456 123456  1
9517 45632 643164 3478643 43 16 431 64453132 689431 746546 15643 1
64543 13146543 13474 314789 4352154 65431 631 654324 65132 89547  34567312 1 1

3 3
0 1 2
1 0 1
2 1 0

3 3
0 0 0
0 0 0
0 0 0

1 1
0

10 10
1 2 300 4 5 6 7 8 9 10
20 19 18 17 16 15 14 13 12 11
21 22 23 24 25 26 27 28 29 30
40 39 38 37 36 35 34 33 32 31
41 42 43 44 45 46 47 48 49 50
60 59 58 57 56 55 54 53 52 51
61 62 63 64 65 66 67 68 69 70
80 79 78 77 76 75 74 73 72 71
81 82 83 84 85 86 87 88 89 90
100 99 98 97 96 95 94 93 92 91

4 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4

4 4
1 2 2 1
1 4 4 1
1 3 3 1
1 2 2 1

3 3
9 1 2
5 6 7
8 4 3

Sample Output

25
1
2
2
4
3
7
4
12
2
27
37
3
1
1
97
4
4
4
*/

這上面是上下左右一個個判斷的,我後來翻別人的程式碼時,發現他們用[4][2]陣列來表示方向,到時候用(for int i=0;i<4;i++)來遍歷4個方向。也挺好的。
//迴圈出四個方面的最長序列然後len[i][j]=max(len[上],下,左,右)+1;
#include <iostream>
#define N 101
using namespace std;
int map[N][N],len[N][N];
int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
int r,c;
int dp(int i,int j){
    if(len[i][j]!=0)return len[i][j];
    int maxx=0,s;
    for(int t=0;t<4;t++){
          int temx=i+dir[t][0],temy=j+dir[t][1];
          if(temx>=0&&temx<r&&temy>=0&&temy<c&&map[temx][temy]<map[i][j]){
              s=dp(temx,temy);
              if(s>maxx)maxx=s;
          }
           
      }
    len[i][j]=maxx+1;
    return maxx+1;
}
 
int main(){
		cin>>r>>c;
        int mx=-1;
        memset(len,0,sizeof(len));
        for(int i=0;i<r;i++){
           for(int j=0;j<c;j++){
			   cin>>map[i][j];
		   }
		}
        for(int i=0;i<r;i++){
           for(int j=0;j<c;j++){
			   len[i][j]=dp(i,j);
			   if(len[i][j]>mx){
			      mx=len[i][j]; 
			   }
		   }         
        }
		cout<<mx;
	    return 0;
}

相關推薦

POJ1088 滑雪動態規劃

題目: Description Michael喜歡滑雪這並不奇怪, 因為滑雪的確很刺激。可是為了獲得速度,滑的區域必須向下傾斜,而且當你滑到坡底,你不得不再次走上坡或者等待升降機來載你。Michael想知道在一個區域中最長底滑坡。區域由一個二維陣列給出。陣列的每個數字代表

動態規劃 POJ1088 滑雪問題

Description Michael喜歡滑雪百這並不奇怪, 因為滑雪的確很刺激。可是為了獲得速度,滑的區域必須向下傾斜, 而且當你滑到坡底,你不得不再次走上坡或者等待升降機來載你。Michael想知道載一個區域中最長底滑坡。 區域由一個二維陣列給出。陣列的每

動態規劃[POJ 1088]滑雪

意思就是把所有點存下來,按照高度排個序, 然後從小到大列舉,然後判斷當前的點的四個方向有沒有存在經過當前點更優的情況,並且那個點的高度比當前點的高度要高如果存在就更新,因為根據大小排了序,所以不會出現不會出現一個點重複統計的情況那麼複雜度是O(n2) #inc

Java滾動數組動態規劃UVA - 11137 - Ingenuous Cubrency

得到 lose math scanner light clas details 狀態 ann 滾動數組優化自己畫一下就明白了。 http://blog.csdn.net/u014800748/article/details/45849217 解題思路:本題利用遞推關系解決。

動態規劃 Codeforces Round #416 (Div. 2) C. Vladik and Memorable Trip

and main spa def esp 動態 return 價值 can 劃分那個序列,沒必要完全覆蓋原序列。對於劃分出來的每個序列,對於某個值v,要麽全都在該序列,要麽全都不在該序列。 一個序列的價值是所有不同的值的異或和。整個的價值是所有劃分出來的序列的價值之和。

動態規劃Codeforces Round #406 (Div. 2) C.Berzerk

[1] space node sca 一個 for 隊列 ber 動態規劃 有向圖博弈問題。 能轉移到一個必敗態的就是必勝態。 能轉移到的全是必勝態的就是必敗態。 轉移的時候可以用隊列維護。 可以看這個 http://www.cnblogs.com/quintessence

動態規劃CDOJ1271 Search gold

mage images sin class png http std ret urn 方格取數。 但由於題意說金幣數<0就死了,就不能繼續轉移。 #include<cstdio> #include<algorithm> #include&l

動態規劃最長公共子序列問題

clas == 搜索 ios for 參考 pan 公式 是否 題目描述: 給定兩個字符串s1s2……sn和t1t2……tn。求出這兩個字符串最長的公共子序列的長度。字符串s1s2……sn的子序列指可以表示為si1si2……sim(i1<i2<……<im)

TarjanLCA動態規劃推導hdu6065 RXD, tree and sequence

and main ack find turn hdu mes ear 高明 劃分出來的每個區間的答案,其實就是連續兩個的lca的最小值。 即5 2 3 4 這個區間的答案是min(dep(lca(5,2)),dep(lca(2,3),dep(lca(3,4))))。 於是d

動態規劃windy數

center log char enter tdi ++ getc windy數 ace BZOJ1026: [SCOI2009]windy數 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 7893 Solved: 3

DFS拓撲排序動態規劃Gym - 100642A - Babs' Box Boutique

關鍵字 dag 在一起 ems class std rst ++i box 給你10個箱子,有長寬高,每個箱子你可以決定哪個面朝上擺。把它們摞在一起,邊必須平行,上面的不能突出來,問你最多擺幾個箱子。 3^10枚舉箱子用哪個面。然後按長為第一關鍵字,寬為第二關鍵字,從大到小

原根動態規劃bitset2017四川省賽 K.2017 Revenge

iostream 我們 eset main pen 乘法 四川 動態 概論 題意: 給你n(不超過200w)個數,和一個數r,問你有多少種方案,使得你取出某個子集,能夠讓它們的乘積 mod 2017等於r。 2017有5這個原根,可以使用離散對數(指標)的思想把乘法轉化成加

Codeforces 949DShake It! 動態規劃

href 動態 ++ dot ref ima scanf ces c++ 參考: http://blog.csdn.net/gjghfd/article/details/77824901 所求的是滿足條件的圖中“不同構”的數量,意味著操作的順序是可以忽略的

動態規劃背包問題

urn 兩個 pro 數組實現 可以轉化 轉化 題目 int 遞增   背包問題無疑是最經典的dp問題,其次就是關於字符串匹配問題,數組最長遞增(減)序列長度等等。背包問題變體很多。   動態規劃問題實際上與備忘錄式深搜有些類似。 1. 0-1背包 題目:   有n個重量和

動態規劃背包問題相關題目

scanf man 初始 ads 無法 ger %d val more 1.poj 1742 Description People in Silverland use coins.They have coins of value A1,A2,A3...An Silverla

動態規劃ZZNU-OJ- 2054 : 油田

tex 搜索 n) 正整數 頁面 復制 最優解 使用 包含 2054 : 油田 (一個神奇的功能:點擊上方文字進入相應頁面) 時間限制:1 Sec 內存限制:32 MiB提交:49 答案正確:6 提交 狀態 討論區 題目描述 在太平洋的一片海域,發現了大量的油田! 為了方

動態規劃最大正方形 (洛谷 P1387 最大正方形)

代碼 log mar 最小 down 思路 計數 -m i++ 輸入格式: 輸入文件第一行為兩個整數n,m(1<=n,m<=100),接下來n行,每行m個數字,用空格隔開,0或1。 輸出格式: 一個整數,最大正方形的邊長。 輸入輸出樣例 輸入樣例: 4 4 0

POJ1390 Blocks 動態規劃

data alt ++ his fin tracking out printf box Blocks Time Limit:?5000MS ? Memory

poj 2385動態規劃

ostream bmi 。。 set row include urn get 定義 poj 2385 Apple Catching Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 1400

動態規劃電路布線問題

bar ref end htm tracking arc tools order 情況下 算法筆記——【動態規劃】電路布線問題 原創 2013年03月14日 09:18:27 標簽: 電路布線 / 算法筆記 / 動態規劃 / 最優子結構 12785