問題描述:
長江遊樂俱樂部在長江上設定了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行是...