Go语言实现Best travel

描述

John and Mary want to travel between a few towns A, B, C … Mary has on a sheet of paper a list of distances between these towns. ls = [50, 55, 57, 58, 60]. John is tired of driving and he says to Mary that he doesn’t want to drive more than t = 174 miles and he will visit only 3 towns.
Which distances, hence which towns, they will choose so that the sum of the distances is the biggest possible to please Mary and John?
Example:
With list ls and 3 towns to visit they can make a choice between: [50,55,57],[50,55,58],[50,55,60],[50,57,58],[50,57,60],[50,58,60],[55,57,58],[55,57,60],[55,58,60],[57,58,60].
The sums of distances are then: 162, 163, 165, 165, 167, 168, 170, 172, 173, 175.
The biggest possible sum taking a limit of 174 into account is then 173 and the distances of the 3 corresponding towns is [55, 58, 60].
The function chooseBestSum (or choose_best_sum or … depending on the language) will take as parameters t (maximum sum of distances, integer >= 0), k (number of towns to visit, k >= 1) and ls (list of distances, all distances are positive or null integers and this list has at least one element). The function returns the “best” sum ie the biggest possible sum of k distances less than or equal to the given limit t, if that sum exists, or otherwise nil, null, None, Nothing, depending on the language. With C++, C, Rust, Swift, Go, Kotlin return -1.

分析

典型的最优问题,可以用动态规划(dynamic programming)实现。
对于目标数组,我们暂时只关注第一个元素。对于该元素,相对于结果数组,只有两种可能:1. 出现在结果数组中,2. 或者不出现在结果数组中。对于第一种情况,问题减治为第一个元素和一个子数组最大和的和。而子数组问题与原数组问题为性质相同的问题,可以通过递归处理。对于第二种情况,问题直接减治为子数组最大和。同样性质相同,可以通过递归处理。最后取两种情况的最大值,即为满足条件的结果。
终止条件及优化:1. 在数组中选出一个满足条件的元素。此时无需继续递归,直接遍历数组即可。2. 数组个数与选择元素个数相同。此时也无需继续递归,直接计算数组所有元素和判断是否满足条件即可。3. 当第一种情况返回结果直接等于最大值,此时无需再尝试第二种情况,直接返回即可。

实现

func max(a, b int) int {
  if a > b { return a }
  return b
}

func ChooseBestSum(t, k int, ls []int) (ret int) {
  if k > len(ls) { return -1 }
  if k == 1 {
    ret = -1
    for _, v := range ls {
      if v <= t && v > ret { ret = v }
    }
    return ret
  }
  if k == len(ls) {
    sum := 0
    for _, v := range ls { sum += v }
    if sum > t { return -1 }
    return sum
  }
  sub1 := ChooseBestSum(t, k, ls[1:])
  if sub1 == t || t <= ls[0] { return sub1 }
  sub2 := ChooseBestSum(t - ls[0], k - 1, ls[1:])
  if sub2 < 0 { return sub1 }
  return max(sub1, sub2 + ls[0])
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值