poj-1661 help jimmy
help jimmy
time limit:1000ms
memory limit:10000k
total submissions:13143
accepted:4363
description
"help jimmy" 是在下圖所示的場景上完成的遊戲。
場景中包括多個長度和高度各不相同的平台。地面是最低的平台,高度為零,長度無限。
jimmy老鼠在時刻0從高於所有平台的某處開始下落,它的下落速度始終為1公尺/秒。當jimmy落到某個平台上時,遊戲者選擇讓它向左還是向右跑,它跑動的速度也是1公尺/秒。當jimmy跑到平台的邊緣時,開始繼續下落。jimmy每次下落的高度不能超過max公尺,不然就會摔死,遊戲也會結束。
設計乙個程式,計算jimmy到底地面時可能的最早時間。
input
第一行是測試資料的組數t(0 <= t <= 20)。每組測試資料的第一行是四個整數n,x,y,max,用空格分隔。n是平台的數目(不包括地面),x和y是jimmy開始下落的位置的橫豎座標,max是一次下落的最大高度。接下來的n行每行描述乙個平台,包括三個整數,x1[i],x2[i]和h[i]。h[i]表示平台的高度,x1[i]和x2[i]表示平台左右端點的橫座標。1 <= n <= 1000,-20000 <= x, x1[i], x2[i] <= 20000,0 < h[i] < y <= 20000(i = 1..n)。所有座標的單位都是公尺。
jimmy的大小和平台的厚度均忽略不計。如果jimmy恰好落在某個平台的邊緣,被視為落在平台上。所有的平台均不重疊或相連。測試資料保證問題一定有解。
output
對輸入的每組測試資料,輸出乙個整數,jimmy到底地面時可能的最早時間。
sample input
1sample output3 8 17 20
0 10 8
0 10 13
4 14 3
23source
poj monthly--2004.05.15 ceoi 2000
中文題,題意還是很簡單的,是男人就下100層。可左可右,只要到地上(高度為0)即可。只是注意有乙個最大高度,超過這個高度就會摔死。wa的經驗告訴我恰好等於這個值是不會摔死的(怒得一發wa)。如果大於這個值,我們可以設定乙個無限大的值來代替摔死這個狀態,這個無限大的值一定要設定的足夠大(wa經驗2 - -)。
這個題分析的時候不是說特別難,但是很麻煩,明顯是dp的寫法,但是總有各種小錯誤,還是**搓的少啊。這裡提供dp的思路:
如果不是剛入門dp,應該有見到過很基礎的dp題:三角形求最大路徑,大概意思如下:
如圖所示的三角形堆,從上到下尋找路徑,只能往兩邊尋找,每個節點有對應的權值,要求找到乙個最大的路徑。
這個題的思路就跟poj-1661很像了。都是從2邊開始。但是1661就難在要判斷下一層是否有台子,如果有是哪乙個台子,以及分左右端點的情況下還要考慮在檯子上移動的距離。不過不論怎麼,我們都應該從最下面的台子向上進行計算。
那麼根據上面的分析我們可以這樣來寫:
1.定義乙個結構體,根據輸入資料,包括左端點座標右端點座標以及相對地面的高度。
2.對於每乙個台子我們進行排序,從上到下排列好,並且賦予每個台子乙個代號i,從最下面的到最上面的是0-n
3.設定2個陣列left、right。left[i]就表示i號台子左端開始向下走到地面的最小長度,right[i]同理。這樣就確定了狀態和值。
4.最終狀態就是直接求最上面的台子的值,比較左右以後,加上剛開始掉下來的時間就行了。
這樣我們可以寫出這樣的**:
struct tai ;
bool cmp(tai a, tai b)
vectorv;
while (n--)
sort(v.begin(), v.end(), cmp);
上面的**就能夠通過排序對台子編號,利用vector的下標來標明每個台子。
下面看一下如何考慮left與right的問題
可以看到,排序後0號台子一定是直接到地面的,那麼這個就是臨界值了,left[0] = v[0].h right[0] = v[0].h。也就是說,我們把端點往下掉以及之後的長度設定為值。那麼這樣考慮第0層是正確的,第一層往後就不對了。如果落到板子上,就上上圖一樣:left[1] = max(left[0],right[0]) + v[1].h - v[0].h,缺少了在板子上移動的距離。同時,這一段移動的距離應該也是要參與比較的,不能只判斷端點處的大小就決定到底走那邊,因為板子上移動的距離也要考慮。
我為什麼要這樣設定狀態,因為對於一塊板子來說,2個端點是確定的,但是落點卻無法考慮,一塊板子可能有上面多個台子的落點,而且落點的具體位置需要複雜的計算。相比而言,比較檯子上的移動距離就簡單的多了,因為落點已經完全確定了。所以可以寫出這樣的**:
for (int i = 0; i < v.size(); i++) else
}else else else
} }}
notai()函式是確定該台子是不是能落到新的檯子上,-1說明直接落到地上了。**如下:
int notai(int up_x, int h, int i, int max)
} return -1;
}
那麼,我們就可以求得一塊台子從左端以及右端向下走的最短的情況,完全不用考慮下面的應該怎麼走,計算的永遠是下面一塊台子的左右端點與在檯子上移動的距離,以此來比較大小,下落的時間是相同的,跟往左往右走無關。
最終判斷的時候,等於再考慮一下剛開始下落點向左右移動的距離。這裡要先確定下落點能落在哪塊板子上,是否能直接落到地面。由於題目不存在無解的情況,所以如果直接落到地面,那麼高度一定是小於等於最大值的。所以有**:
int flag = notai(bx, bh, v.size(), max);
if (flag == -1) else
int ans = bh - v[flag].h;
int left_det = left[flag] + bx - v[flag].x1;
int right_det = right[flag] + v[flag].x2 - bx;
if (left_det < right_det) else
cout << ans << endl;
flag就是表示直接落到的台子編號。
#include#include#include#include#include#define time std::ios::sync_with_stdio(false);
#define ll long long
#define max 666666
#define max_num 100005
using namespace std;
struct tai ;
bool cmp(tai a, tai b)
vectorv;
int notai(int up_x, int h, int i, int max)
} return -1;
}int min(int a, int b)
int main()
sort(v.begin(), v.end(), cmp);
int flag = notai(bx, bh, v.size(), max);
if (flag == -1) else else
}else else else }}
temp = notai(v[i].x2, v[i].h, i, max);
if (temp == -1) else
}else else else }}
}int ans = bh - v[flag].h;
int left_det = left[flag] + bx - v[flag].x1;
int right_det = right[flag] + v[flag].x2 - bx;
if (left_det < right_det) else
cout << ans << endl;
} v.clear();
} system("pause");
return 0;
}
poj1661 Help Jimmy dp動態規劃
help jimmy description help jimmy 是在下圖所示的場景上完成的遊戲。場景中包括多個長度和高度各不相同的平台。地面是最低的平台,高度為零,長度無限。jimmy老鼠在時刻0從高於所有平台的某處開始下落,它的下落速度始終為1公尺 秒。當jimmy落到某個平台上時,遊戲者選擇...
POJ1661Help Jimmy(動態規劃)
description help jimmy 是在下圖所示的場景上完成的遊戲。場景中包括多個長度和高度各不相同的平台。地面是最低的平台,高度為零,長度無限。jimmy老鼠在時刻0從高於所有平台的某處開始下落,它的下落速度始終為1公尺 秒。當jimmy落到某個平台上時,遊戲者選擇讓它向左還是向右跑,它...
poj 1661 Help Jimmy 動態規劃
題意 給n個用左端點 右端點 高度標識的平台,問乙個下落速度,移動速度均為1的點下落到地面的最小時間,其中每次下落距離不能超過輸入值max.分析 動態規劃ldp i 表示從第i塊木板左邊下落到地面的最小時間,rdp i 表示從第i塊木板右邊下落到地面的最小時間。poj 1661 sep9 inclu...