租用遊艇問題
成績 | 10 | 開啓時間 | 2020年03月24日 星期二 23:15 |
折扣 | 0.8 | 折扣時間 | 2020年04月21日 星期二 23:55 |
允許遲交 | 否 | 關閉時間 | 2020年04月21日 星期二 23:55 |
問題描述: 長江遊艇俱樂部在長江上設置了n個遊艇出租站1,2,…,n. 遊客可在這些遊艇出租站租用遊艇, 並在下游的任何一個遊艇出租站歸還遊艇. 遊艇出租站i到出租站j之間的租金爲r(i,j), 1<=i<j<=n. 試設計一個算法, 計算出從遊艇出租站1到遊艇出租站n所需的最少租金, 並分析算法的計算複雜性.
算法設計: 對於給定的遊艇出租站i到遊艇出租站j的租金r(i,j), 1<=i<j<=n. 計算出租站1到n所需的最少租金.
數據輸入: 第1行有一個正整數n, n<=200, 表示有n個遊艇出租站. 接下來n-1行是r(i,j), 1<=i<j<=n.
結果輸出: 遊艇出租站1到n最少租金.
測試輸入 | 期待的輸出 | 時間限制 | 內存限制 | 額外進程 | |
---|---|---|---|---|---|
測試用例 1 |
|
|
1秒 | 64M | 0 |
本題可以說是區間DP | 1:矩陣鏈乘問題(含優化) —— 例題:矩陣鏈乘、合併石子的一個小小部分(看完這一題再去看鏈接就豁然開朗~)。不過我是A完了那一題再來些這個的,就是一個入門級的DP,小菜一碟啦~
處理輸入
一個有n個節點組成的線段,給出了任意兩不同節點之間的收費r。對節點分別編號爲 1..n,可以用二維數組 r[ i ][ j ] 表示節點 i 到節點 j 的收費r。
動態分析
其實對於一個長度爲 l 的線段 r[ i ][ j ] (其中有j = i + l),它可以由兩段長度小於 l 的子線段組成,且若要原線段是最優解(花費爲最小值),其兩個子線段也應該是最優解。故此模型滿足最優子結構的性質,且容易看出,很多子結構是重疊的,此模型又具備重疊子問題的性質。故,本題採用動態規劃求解啦~
模型建立
採用一個二維數組 dp[ i ][ j ] 記錄節點 i 到節點 j 的最優解(最小收費r)。根據上面對最優子結構分析,我們應該先求出子問題的最優解再推斷出原問題的最優解,故可以使用自底向上的方法來實現。先從 l = 2 開始分析,依次上推到 l = n即得到答案 dp[1][n]。狀態轉移方程如下:
不要忽略了節點 i 到節點 j 不劃分子問題的情況,直接取r[ i ][ j ]。爲方便起見,我們將dp[ i ][ j ]先賦值爲r[ i ][ j ]即可,之後在比較的過程中會選取最小的。
完整AC代碼
#include <cstdio>
#include <algorithm>
#define MAXN 205
using namespace std;
int main() {
int n, r[MAXN][MAXN], dp[MAXN][MAXN];
scanf("%d", &n);
/* 處理輸入 */
for (int i = 1; i < n; i++)
for (int j = i + 1; j <= n; j++)
scanf("%d", &r[i][j]);
/* 自底向上求解 */
for (int l = 1; l < n; l++) { //長度l:1..n
for (int i = 1; i <= n - l; i++) { //遍歷所有長度爲l的情況
int j = i + l;
dp[i][j] = r[i][j]; //賦予初值(不斷開的情況)
for (int k = i + 1; k < j; k++) //尋找中間點斷開,更新最優的
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
}
}
printf("%d\n", dp[1][n]);
}
有任何問題歡迎評論交流,如果本文對您有幫助不妨點點贊,嘻嘻~
end
歡迎關注個人公衆號“ 雞翅編程 ”,這裏是認真且乖巧的碼農一枚。
---- 做最乖巧的博客er,做最紮實的程序員 ----
旨在用心寫好每一篇文章,平常會把筆記彙總成推送更新~