计算机算法分析与设计(10)---租用游艇问题(含C++代码)


1、问题描述

 长江游艇俱乐部在长江上设置了 n n n 个游艇出租站 1 , 2 , … … , n 1,2,……,n 1,2,……,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站 j j j 之间的租金为 r ( i , j ) , 1 < = i < j < = n r(i,j),1<=i<j<=n r(i,j)1<=i<j<=n。试设计一个算法,计算出从游艇出租站 1 1 1 到游艇出租站 n n n 所需的最少租金。

 输入格式:第 1 1 1 行中有 1 1 1 个正整数 n ( n < = 200 ) n(n<=200) nn<=200,表示有 n n n 个游艇出租站。接下来的第 1 1 1 到第 n − 1 n-1 n1 行,第 i i i 行表示第 i i i 站到第 i + 1 i+1 i+1 站、第 i + 2 i+2 i+2 站、 … 、第 n n n 站的租金。

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

输入样例:
3
5 15
7
输出样例:
12

2、代码分析(用动态规划思路)

 1. 本题采用动态规划思路来解决,需要写出递归方程。

 2. 本题的思路和矩阵链相乘思路很相似,但递推方程不一样。租用游艇:比如从 1 1 1 3 3 3,然后从 3 3 3 n n n ;矩阵链:比如从 1 1 1 3 3 3,那么接下来就是 4 4 4 n n n

 3. 思路:中间位置划分:i -> k ->j。即分为 r[i][j] -> r[i][k] + r[k][j]。由于是最少租金,初始时 dp[i][j] = r[i][j]。状态转移方程为 dp[i][j] = min(dp[i][k] + dp[k][j]), k = [i+1 , j-1]

时间复杂度 O ( n 3 ) O(n^3) O(n3)

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n, r[300][300], dp[300][300];
	cin >> n;
	
	for(int i = 1; i <= n; i++) //出租站i到i的租金为0 
	{
		r[i][i] = dp[i][i] = 0;
	}
	
	for(int i = 1; i <= n - 1; i++) //输入出租站i到i+1的租金 
	{
        for(int j = i + 1; j <= n; j++){
            cin >> r[i][j];
            dp[i][j] = r[i][j];
        }
    }
    
     for(int i = 1; i <= n - 1; i++)
	 {
        for(int j = i + 1; j <= n; j++)
		{ 
            for(int k = i + 1; k <= j - 1; k++)
			{
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
            }
        }
    }
    
    cout << dp[1][n];
    return 0;
} 

3、代码分析(用Dijkstra算法思路)

 1. 由于Dijkstra算法用于最短距离,所以这里我们用距离代替租金(本质是一样的)。

 2. 先用一个 d i s [ j ] dis[j] dis[j] 来存储站 1 1 1 到站 2 2 2,站 3 3 3 … 站 n n n 的最短距离,刚开始 d i s dis dis 的初始距离就是 r [ 1 ] [ j ] r[1][j] r[1][j] 的距离。

 3. 之后我们遍历查找确定其他的最小距离。因为前面 1 1 1 2 2 2 已经确认所以我们从 i=3 开始, j j j 从确定好的里面进行挑选,当 dis[i]>dis[j]+r[j][i] 时进行更新。最后输出 d i s [ n ] dis[n] dis[n]

时间复杂度 O ( n 2 ) O(n^2) O(n2)

#include<bits/stdc++.h>
using namespace std;
//这里用距离代替租金 
int main()
{
	int n;
	cin >> n;
	int r[n][n], dis[n];
	
	for(int i = 1; i <= n; i++) //出租站i到i的距离为0 
	{
		r[i][i] = 0;
	}
	
	for(int i = 1; i <= n - 1; i++) //输入出租站i到i+1的距离 
	{
        for(int j = i + 1; j <= n; j++){
            cin >> r[i][j];
        }
    }
    
    dis[0] = dis[1] = 0;
    for(int j = 2; j <= n; j++)
	{
		dis[j] = r[1][j]; //dis的初始距离就是r[1][j]的距离
	}
	
	for(int i = 3; i <= n; i++)
	{
		for(int j = 1; j <= i-1 ; j++)
		{
			if(dis[i] > dis[j] + r[j][i])
			{
				dis[i] = dis[j] + r[j][i];
			}
		}
	}
	cout << dis[n];
    return 0;
} 
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冒冒菜菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值