#53750: Python解


asa241702@gmail.com (帆柚柚~喵~~)

學校 : 不指定學校
編號 : 304743
來源 : [42.79.234.216]
最後登入時間 :
2025-03-13 19:46:10

題意

  • 有一排大樓,高度依序為 h1,h2,…,hn。

  • 滑翔表演要從某棟大樓開始,往右邊滑翔

  • 為了安全,滑翔路徑的高度必須 嚴格遞減(每次滑到的下一棟大樓都要比前一棟矮)。

  • 問你:可以找到的 最長滑翔路徑 長度是多少?

換句話說,就是:
在數列 h1,h2,…,hn裡,找一個往右、嚴格遞減的最長子序列(Longest Decreasing Subsequence, LDS),但是這個子序列必須連續往右(不能往左,也不能跳回去)。

思考

這題跟 最長嚴格遞減子序列 很像,但有個限制:

  • 只能朝右滑翔,所以我們不是找「任意子序列」,而是找「從左到右的連續路徑」。

更準確說法:
對於每個大樓 i,我們可以嘗試從它開始,一直往右找比它低的樓,組成一條遞減路徑,直到不能繼續為止。然後取所有路徑中的最長。

演算法

其實這就是典型的 動態規劃(DP) 問題。
我們可以定義:

dp[i]=以第i棟大樓作為起點時,能走出的最長滑翔路徑長度dp[i] = 以第 i 棟大樓作為起點時,能走出的最長滑翔路徑長度dp[i]=以第i棟大樓作為起點時,能走出的最長滑翔路徑長度

轉移方式:

  • 從 i 之後的所有大樓 j (j>i) 中,如果 h[j]<h[i],
    那麼我們可以往 j 前進,於是:

dp[i]=1+max⁡(dp[j]) (其中 h[j]<h[i])

  • 如果沒有比 h[i]矮的樓,那麼:

dp[i]=1

最後答案就是:

max⁡(dp[i])for all i

程式碼範例 (Python)

def longest_slide(heights):
    n = len(heights)
    dp = [1] * n  # 每棟大樓至少能待在自己
    
    # 從右往左計算
    for i in range(n - 1, -1, -1):
        for j in range(i + 1, n):
            if heights[j] < heights[i]:
                dp[i] = max(dp[i], 1 + dp[j])
    
    return max(dp)

# 測試
heights = [10, 9, 4, 5, 8, 3, 2, 1]
print(longest_slide(heights))  # 輸出應該是 5 (例如 10 -> 9 -> 4 -> 3 -> 2)

時間複雜度

  • 這樣寫是 O(n²)

  • 如果 n 很大(例如 10^5),就需要更進階的方法(像二分法優化的 Longest Decreasing Subsequence 演算法,能降到 O(n log n))。