长江一日游-出租游艇

题目:长江港口出租游艇,有1,2….n个出租站点,游客可在这个某出租站点租游艇,然后在下游任一出租站点归还游艇。游艇出租站i到j的出租费用为r(i,j);1<=j<j<=n,计算港口1到n的最小费用。

Input

第 1 行中有 1 个正整数 n(n<=200) ,表示有 n个游艇出租站。

接下来的n-1 行是r(i,j), r(i,j)为整数,1 ≤ i < j ≤ n。

Output

输出从游艇出租站1到游艇出租站n所需的最少租金。

Sample Input

3
5 15
7

Sample Output

12

直接保存起点到每个点的最少租金

分析:假设出租站点1到出租站点n的最短费用不是为1到n的直通费用,就是说最短费用是在1到n中间,至少在某一个出租点还了游艇,然后又继续租游艇到站点n,所以最少费用满足min=min(Min(i,j)+Min(j,n)),1<j<n;所以此题满足动态规划的最优子结构性质。当我们求出租站1到出租站n的最少费用时候,我们需要知道出租站2到出租站n的最少费用,并且需要知道3->n的最少费用,当我们求出租站2到出租站n的最少费用的时候,又需要知道出租站3到出租站n的最少费用,所以此题也满足动态规划的第二个性质:子问题重叠!

自底向上
s[i][j]存的从i到j的最少租金

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<bits/stdc++.h>
#define MAX 100
using namespace std;
int d[MAX][MAX],m[MAX][MAX],s[MAX][MAX];
void print(int i,int j){
if(s[i][j]==0) {
cout<<j<<"--";
return;
}
print(i,s[i][j]);
print(s[i][j],j);
}
int main(){
int n;
cin>>n;
memset(s,0,sizeof(s));
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++)
{
cin>>d[i][j];
m[i][j]=d[i][j];
}
}
for(int d=3;d<=n;d++){
for(int i=1;i<=n-d+1;i++){
int j=i+d-1;
for(int k=i+1;k<j;k++){
if(m[i][k]+m[k][j]<m[i][j])
{
s[i][j]=k;
m[i][j]=m[i][k]+m[k][j];
}

}
}

}
cout<<1;
print(1,n);
cout<<"cost:"<<m[1][n]<<endl;

}

自顶向下的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/ 港口最少费用.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <stdio.h>
#include <limits.h> //有个表示int类型最大值的宏在这个头文件里面

int FindMinest(int (*p)[10], int (*m)[10], int k, int n);
int Min(int a, int b);
int main()
{
int n;
int p[10][10] = { 0 }; //保存出租站之间的直通费用
int m[10][10] = { 0 }; //保存出租站之间的最短费用
scanf_s("%d", &n);
for (int i = 0; i < n-1; ++i) {
for (int j = i+1; j < n; ++j) {
scanf_s("%d", &p[i][j]); //输入出租站之间的直通出租费用
}
}
int min = FindMinest(p, m, 0, n-1);
printf("%d", min);
return 0;
}
//自顶向下的方法
int FindMinest(int(*p)[10], int(*m)[10], int k, int n) {//这个函数的作用就是找到港口K到港口n的最小费用
int min = INT_MAX;
if (k == n) {
return 0;
}
if (m[k][n] > 0) {
return m[k][n];
}
for (int i = k + 1; i <= n; ++i) {
min = Min(min, p[k][i] + FindMinest(p, m, i, n));

}
m[k][n] = min;
return min;
}
int Min(int a, int b) {
return a < b ? a : b;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>  
using namespace std;
#define N 210
int cost[N][N];
int m[N];

int main()
{
int n,i,j;
while(cin>>n)
{
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++)
cin>>cost[i][j];
m[1]=0;
int min;
for(i=2;i<=n;i++)
{
min=cost[1][i];
for(j=1;j<=i-1;j++)
{
if(m[j]+cost[j][i]<min)
min=m[j]+cost[j][i];
}
m[i]=min; //m数组存储的是到每个点的最小租金,这是个数组而不是一个数,在计算到达一个新的游艇租赁点时,之前的每一个点的最小租金都会用到
}
cout<<m[n]<<endl;
}
return 0;
}