剩下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[i−1][j],dp[i−1][j−songs[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
}