问题描述
长江游艇俱乐部在长江上设置了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行中有1个正整数n(n<=200),表示有n个游艇出租站。接下来的n-1行是r(i,j),1<=i<j<=n。
(例如: 3
5 15
7
表示一共有3个出租站点,其中
第1个站点到第2个的租金为5
第1个站点到第3个的租金为15
第2个站点到第3个的租金为7)
证明最优性原理
假设从游艇出租站1到出租站n的最优方案为在x1,x2,x3…xk处归还并在此租用。若x1,x2,x3…xk-1不是游艇从出租站1到出租站n-1的最优方案,则设其最优方案为S,则费用应比假设的最优方案更低。因此,x1,x2,x3…xk-1必然为游艇从出租站1到出租站n-1的最优方案。
划分子问题
初始子问题:第一个站点到第一个站点的租金为0
下一阶段的子问题:
第一个站点到第二个站点的租金为5
第一个站点到第三个站点:1,直接从第一个站点到第三个战斗的租金15;2,第一个站点,第二个战点再到第三个站点的租金5+7=12;上述情况取最小值。
…
确定动态方程
令arc[i][j]表示直接从第i个站点到第j个站点的租金;
令cost[i]表示从第一个站点到第i个站点所需最少租金;
【1】初始子问题,当i=1时,cost[1]=0;
【2】下一阶段的子问题,当i>1时,
cost[i]=min{arc[1][i],cost[k]+arc[k][i]} [其中1<k<=i]
注意
不要陷入误区,求第一个站点到第i个站点时,取1-3-i,则3–i阶段取其直接到达的租金,而非在这种情况下考虑3–i如何最优。后续过程中考虑1–4--i,1–5--i……的过程中,已将上述情况考虑在内。动态规划,即在上一步最优的情况下直接走下一步,记录所有的情况,并进行比较。
源代码
#include<iostream>
#include<fstream>
using namespace std;
//3
//5 15
//7
//表示一共有3个出租站点,其中
//第1个站点到第2个的租金为5
//第1个站点到第3个的租金为15
//第2个站点到第3个的租金为7
int main()
{
int n; int fare[200][200];
int cost[200];
ifstream f1("C:\\Data\\3.txt");
ofstream f2("C:\\Data\\4.txt");
f1 >> n;
for (int a = 0; a < n; a++)
{
for (int b = a; b < n; b++)
{
if (a == b)
{
fare[a][b] = 0;
}
else
{
f1 >> fare[a][b];
}
}
}
cost[0] = 0;
if(n>1)
cost[1] = fare[0][1];
if (n > 2) {
int temp = 0;
for (int i = 2; i < n; i++)
{
cost[i] = fare[0][i];
}
for (int a = 2; a < n; a++)
{
for (int b = a - 1; b > 0; b--)
{
temp = cost[b] + fare[b][a];
if (temp < cost[a])
cost[a] = temp;
}
}
}
cout << "从游艇租用站1到租用站" << n << "所需最少租金为" << cost[n-1] << "\n";
f2<< cost[n-1] << "\n";
f1.close();
f2.close();
return 0;
}