劲爆金曲解析

剩下n首歌,t秒时间,问最多能唱几首的前提下,最长时间

输出最多歌数和最长时间

思路:

典型的动归问题,假设我们现在要唱j秒,然后当我们新加入一首歌时,我们会判断能否加入。

  • 如果加入那么最多能唱的歌数为j减去这首歌的时间内能最多唱的数量+1
  • 如果不加入,那么就是未加入这首歌时,j秒内最多能唱的数量

因此,我们推出公式
d p [ i ] [ j ] = m a x { d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − s o n g s [ i ] ] + 1 } dp[i][j]=max\{dp[i-1][j],dp[i-1][j-songs[i]]+1\} dp[i][j]=max{dp[i1][j],dp[i1][jsongs[i]]+1}
上面i为第i首歌,j为时间,songs为每首歌对应的时长

代码实现:

// KTV n首歌, 剩余t时间,songs为每首歌的时长
// 金曲的时长为687s
func KTV(n, t int, songs []int) (int, int) {
   number := make([][]int, len(songs)+1)
   for k, _ := range number {
      number[k] = make([]int, t)
   }
   number[0][0] = 0 // 0首0s
   for i := 1; i <= len(songs); i++ {
      for j := 0; j < t; j++ {
         number[i][j] = number[i-1][j]
         if j >= songs[i] {
            // 当前的j满足唱这首歌,确保指针不为负
            number[i][j] = max(number[i][j], number[i-1][j-songs[i]]+1)
         }
      }
   }
  
}

上面的代码实现了number的初始化,那么最长歌数一定是在number[n]数组里面,那么最长时间呢?

因为number[i][j]表示的为j秒内最多可唱的歌,也就是当j1>j2时,那么number[i][j1]>=number[i][j2],因此我们无法知道这个j是否为唱这么多首歌所需的时间

解决思路:

我们期望的时间肯定为t-1,那么,我们遍历每一首歌,如果当前这一首能唱,并且满足number中在唱这首歌后刚好为当前歌数-1,那么就代表能选择这首

代码实现:

func total_time(t, n int, songs []int, number [][]int) int {
	// 当前剩下的时间t,总的时间
	for i := 0; i < n; i++ {
		if t >= songs[i] && number[i][t] == number[i][t-songs[i]]+1 {
			return songs[i] + total_time(t-songs[i], n, songs, number)
		}
	}
	return 0
}

总代码实现:

// KTV n首歌, 剩余t时间,songs为每首歌的时长
// 金曲的时长为687s
func KTV(n, t int, songs []int) (int, int) {
   number := make([][]int, len(songs)+1)
   for k, _ := range number {
      number[k] = make([]int, t)
   }
   number[0][0] = 0 // 0首0s
   for i := 1; i <= len(songs); i++ {
      for j := 0; j < t; j++ {
         number[i][j] = number[i-1][j]
         if j >= songs[i] {
            // 当前的j满足唱这首歌,确保指针不为负
            number[i][j] = max(number[i][j], number[i-1][j-songs[i]]+1)
         }
      }
   }
   ans := total_time(t-1, n, songs, number)
   return number[n][ans] + 1, ans + 678 // 最长时间,最多歌曲
}

func total_time(t, n int, songs []int, number [][]int) int {
   // 当前剩下的时间t,总的时间
   for i := 0; i < n; i++ {
      if t >= songs[i] && number[i][t] == number[i][t-songs[i]]+1 {
         return songs[i] + total_time(t-songs[i], n, songs, number)
      }
   }
   return 0
}

func max(x, y int) int {
   if x > y {
      return x
   }
   return y
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值