/*
问题描述
长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1i<jn。试设计一个算法,计算出从游艇出租站1到游艇出租站n所需的最少租金。
计算从首站到末站的最小费用
第一行数字表示有n个站点
后边的第x行第y列的数字表示从第x站到第x+y站的费率
输入文件示例 输出文件示例
input.txt output.txt
3
5 15 12
7
input.txt output.txt
4 15
3 7 19
5 13
8
*/
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
//在测试条件下最大值设置为6已经够用
//也可以更大
const int max = 6;
//参数begin、end代表索引(index),从0开始而非从1开始
//参数begin、end分别为要求解的起始站点和最终站点的索引
//使用dp[x][y]存储从x到y的最小费用
//使用port[x][y]存储题目给出的直接从x到y的价格,
//实际上dp与port都只用了一个三角矩阵,但为了方便还是分配整个矩阵的空间
//返回值仅对于最上层的调用有意义,内部的递归调用的返回值没有用处
//事实上也可以不要返回值,因为返回值就在dp[begin][end]中,可以取出
int solve(int dp[max][max], int port[max][max], int end, int begin) {
//临时变量,为了VC中调试时鼠标指上去观察数值,实际上可以不要
int ret = -1;
//从站点出发到自身,不花钱,记录在dp中
if (begin == end) {
dp[begin][end] = 0;
ret = dp[begin][end];
return 0;
}
//如果两站相邻,则直接到达的费用就是最小费用,记录在dp中
else if (begin == end - 1) {
dp[begin][end] = port[begin][end];
ret = dp[begin][end];
return dp[begin][end];
}
//如果两站相隔较远,则比较麻烦
//出发站到末站的最小费用是直接到达和经过其他站转到的各种情况的费用中最小的那个
//A到D的最小费用为min(A到B的最小费用+B到D的最小费用,
//A直接到C 的最小费用+C到D的最小费用,A直接到D的最小费用)
else if (end - begin > 1) {
int min = port[begin][end]; //直接到达的费用总是已知的
//用一个循环遍历查找最小值
for (int i = 1; i < end - begin; i++) {
//如果中转站到末站的费用还是未知,则先递归算出来再使用
if (dp[begin + i][end] == -1) {
solve(dp, port, end, begin + i);
}
//如果起始站到中转站的费用还是未知,则先递归算出来再使用
if (dp[begin][begin + i] == -1) {
solve(dp, port, begin + i, begin);
}
//如果到某个中转站的费用更小,则把最小值更新为这个费用
if (min > dp[begin + i][end] + dp[begin][begin + i]) {
min = dp[begin + i][end] + dp[begin][begin + i];
}
}
//把最小费用填入表格,以供使用
dp[begin][end] = min;
}
else {
//其他情况提示出错
cout << "ERROR!" << endl;
getchar();
getchar();
exit(-1);
}
//现实计算结果以便检查,并返回
cout << dp[begin][end] << endl;
return dp[begin][end];
}
int main() {
//读取文件
fstream fs;
fs.open("input.txt", ios::in);
int n; //站点数量
int dp[max][max]; //存放任意两站之间的最小费用的表
int port[max][max]; //存储初始信息,各站点直达其他站点的费用
fs >> n;
cout << n << endl;
//初始化,以-1为空值
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++) {
dp[i][j] = -1;
port[i][j] = -1;
}
}
//读取并储存第x站到第y站的费率
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
fs >> port[i][j];
cout << port[i][j] << '\t';
}
cout << endl;
}
//结束读取,关闭文件
fs.close();
int ret = solve(dp, port, n - 1, 0);
//结果写入到文件
fs.open("output.txt", ios::out);
fs << ret;
fs.close();
cout << ret << endl;
cout << "Finish" << endl;
cin >> n;
return 0;
}