问题描述:
游艇租用问题:长江旅游俱乐部在长江上设置了N个游艇出租站0,1,2,…,N-1,游客在这些站中租用游艇,并在下游的任何一个游艇出租站归还,游艇出租站i到游艇出租站j之间的租金为fee(i,j),0≤i<j≤N-1;试使用动态规划法求出从游艇出租站0到游艇出租站N-1所需的最少租金;
实现提示:
设游艇出租站有N个,而且每两个站的租金都是不一样的,用f(i,j)表示每两个站之间的租金费用。当要租用游艇从一个站到另外一个站时,采取不同的停靠站策略就有不同的租金。例如从第一个站到第三个站,租金是15元,但是第一个站到第二个站的租金只需5元,第二到第三个站的租金要7元,因此可采用先到第二个站,把游艇归还,然后再从第二个站租用游艇到第三个站,因此我们总共需要的费用就是5+7=12元,比直接从第一个站到第三个站要花15元更经济,也就是最少花费。
这是一个优化问题,并且具有最优子结构,表示前n-1个站的最优解,那么前n个站的最优解一定包含前n-1个站的最优解,并且它们具有重叠性。
可以参考课本的“多源点最短路径问题”的解法。设用数组minFee[n][n]表示站点间的最少租金,fee[n][n]表示站点间的直达租金,minFee初始与fee相等。可推导出动态规划函数:
minFee[i][j]=min{Fee[i][j],minFee[i][k]+minFee[k][j]} 0≤k≤n-1
如下为租金费用, 为了方便检验结果的正确性,请用如下租金矩阵,从0到5站的最优结果为17元。
int fee[n][n]=
{{0,3,15,18,29,34},
{3,0,1, 17,18,23},
{15,1,0,10,12,15},
{18,17,10,0,4, 7},
{29,18,12,4,0, 1},
{34,23,15,7,1, 0}};
完整代码:
#include <iostream>
#include<stdio.h>
#include<windows.h>
#include<iomanip>
using namespace std;
#define n 6
void floyd(int fee[n][n], int minFee[n][n])
{
int i, j, k;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
minFee[i][j] = fee[i][j];
for (k = 0; k < n; k++)//进行n次迭代
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
if (minFee[i][k] + minFee[k][j] < minFee[i][j])
minFee[i][j] = minFee[i][k] + minFee[k][j];
}
int main()
{
int p, q;
int fee[n][n]{ {0,3,15,18,29,34},
{3,0,1, 17,18,23},
{15,1,0,10,12,15},
{18,17,10,0,4, 7},
{29,18,12,4,0, 1},
{34,23,15,7,1, 0} };//租金矩阵
int minFee[n][n];
LARGE_INTEGER nFreq;
LARGE_INTEGER nBeginTime;
LARGE_INTEGER nEndTime;
double time;
QueryPerformanceFrequency(&nFreq);
QueryPerformanceCounter(&nBeginTime);
floyd(fee,minFee);
QueryPerformanceCounter(&nEndTime);
time = (double)(nEndTime.QuadPart - nBeginTime.QuadPart) * 1000000000 / (double)(nFreq.QuadPart);
cout <<"从0到5站的最少花费为"<<minFee[0][5]<<endl;
cout <<"程序运行时间(纳秒)"<<time;
}
运行结果: