動態規劃 遊艇租用問題

2021-07-07 06:20:41 字數 3636 閱讀 7774

問題描述:

長江遊樂俱樂部在長江上設定了n個遊艇出租站,遊客可以在這些遊艇出租站用遊艇,並在下游任何乙個遊艇出租站歸還遊艇,遊艇出租站i到j之間的租金是rent(i,j),其中1<=i

這是一道典型的動態規劃問題。解題的思路是,既然要得到最小的花費,那麼就從最底層開始,逐層向上計算每兩個站之間的最小花費,並記錄在陣列中,有記錄的就不必再算了。其中兩個站可能是相鄰的,也可能不是相鄰的。然後要得到方案,就需要對費用進行遞迴檢測,比如:如果j、k兩站之間的最小費用為m,但是j、k兩站之間的某一站p滿足:jp最小費用+pk最小費用等於jk最小費用,同時jk最小費用不等於由j直接到k的費用,則這個p站肯定是其中乙個租船點。如果jk最小費用等於由j直接到k的費用,那麼j和k必定是兩個租船點,且其中沒有租船點。在遞迴的過程中將這些租船點記錄下來,就得到了最優方案。

**如下:

#include #include #include #define n 200

using namespace std;

int p[n][n]; //p[i][j]為i到j的最小費用

int r[n][n]; //儲存資料

int mark[n][n]; //記錄是否已經計算過最小費用,避免重複計算

int smallestfee(int start, int ende); //求最小費用

void findpath(int start, int ende); //求最小費用方案

int answer[n];

int main()

smallestfee(1, n);

printf("smallest cost: %d\n", p[1][n]); //輸出最小費用

//找出最優解

findpath(1, n);

printf("path: 1->");

for(int i = 1; i < n; ++i)

if(answer[i] != 0) printf("%d->", answer[i]);

printf("%d\n\n", n);

while(getchar() != '\n') //剔除空格,為下一次測試做準備

continue;

}return 0;

}int smallestfee(int start, int ende)

p[start][ende] = r[start][ende]; //假設直接從start到ende為最小花費

int k, x1, x2;

for(k = start + 1; k < ende; ++k) //找從start到ende的最小花費

mark[start][ende] = 1; //已經計算過標記為1

return p[start][ende];

}void findpath(int start, int ende)

for(int k = start + 1; k < ende; ++k)

}return;

}

然而上面這種簡單的帶備忘的樸素分治演算法,效率並不高,最差勁的是在求最小花費的過程中,不能同時構建最優方案。下面給出一種更好的方法。

這種方法假定第一次還的位置為k,從1直接到k是最優的(k從2到n迴圈)。然後遞迴呼叫此方法,求得k到n的最優方案和花費。這種方法是一種自頂向下的計算方法,也用到了備忘錄。待會兒再給出一種非遞迴的自底向上的方法。

#include #include #include #define n 200

using namespace std;

int r[n][n]; //儲存資料

int p[n][n]; //記錄最小花費

int smallestfee(int start, int n); //求最小費用

int answer[n];

int main()

printf("smallest cost: %d\n", smallestfee(1, n)); //輸出最小費用

//輸出方案

printf("path: 1->");

for(int i = 2; i < n; ++i)

if(answer[i] != 0) printf("%d->", answer[i]);

printf("%d\n\n", n);

while(getchar() != '\n') //剔除後續字元,為下一次輸入做準備

continue;

}return 0;

}/*自頂向下遞迴計算*/

int smallestfee(int start, int n)

int smallest = 1 << 10;

int x;

for(int k = start + 1; k <= n; ++k)

}answer[x] = x; //記錄最優的歸還站點位置

p[start][n] = smallest; //記錄最優花費

return smallest;

}

上面兩種遞迴方法,因為帶備忘錄,所以沒有重複計算,計算最小花費的時間複雜度均為o(n²),但第二種更好一些,因為在計算的過程中就能構建最優方案,而且第一種還用另乙個函式計遞迴求解了最優方案。

下面給出一種非遞迴的方法,很容易知道時間複雜度也為o(n²),但是不需要備忘錄,其在求解最小費用時,同時能夠構造最優解。這是一種自底向上的方法。假若把n個站從左到右排成一排,左邊為1(起點),右邊為n(終點)。先計算1到k的最優值,在根據1到k的最優值,計算1到k+1的最優值,最後得到1到n的最優值。

**如下:

#include #include #include #define n 200

using namespace std;

int r[n][n]; //儲存費用資料

int p[n][n]; //記錄最小花費

int smallestfee(int start, int n); //求最小費用

int answer[n];

int main()

printf("smallest cost: %d\n", smallestfee(1, n)); //輸出最小費用

//輸出方案

printf("path: 1->");

for(int i = 2; i < n; ++i)

if(answer[i] != 0) printf("%d->", answer[i]);

printf("%d\n\n", n);

while(getchar() != '\n') //剔除後續字元,為下一次輸入做準備

continue;

}return 0;

}/*自底向上計算*/

int smallestfee(int start, int n)

}p[1][i] = x; //記錄最少花費

answer[temp] = temp; //記錄最優方案的歸還站點

}return p[start][n];

}

後面兩種方法的思路是在看《演算法導論》動態規劃章節的過程中得來的,如果文中有錯誤請批評指正。

動態規劃 遊艇租用問題,C

採用動態規劃的思想完成以下任務 遊艇租用問題 問題描述 長江遊艇俱樂部在長江上設定了n個遊艇出租站1,2,n。遊客可在這些遊艇出租站租用遊艇,並在下游的任何乙個遊艇出租站歸還遊艇。遊艇出租站i到遊艇出租站j之間的租金為r i,j 1 i include using namespace std int...

動態規劃 遊艇租用問題(c )

問題描述 長江遊艇俱樂部在長江上設定了n個遊艇出租站1,2,n。遊客可在這些遊艇出租站租用遊艇,並在下游的任何乙個遊艇出租站歸還遊艇。遊艇出租站i到遊艇出租站j之間的租金為r i,j 1i輸入檔案示例 輸出檔案示例 input.txt output.txt312 5 15 7input.txt ou...

cg租用遊艇問題 動態規劃

問題 長江遊艇俱樂部在長江上設定了n個遊艇出租站1,2,3 n。遊客可以在這些遊艇出租站用遊艇,並在下游的任何乙個遊艇出租站歸還遊艇。遊艇出租站i到遊艇出租站j之間的租金為r i,j 1 i試設計乙個演算法,計算從遊艇出租站1到出租站n所需的最少租金。資料輸入 第一行表示有n個站點。接下來n 1行是...