您的位置:首页 > 其它

hihocoder 1532 最美和弦 (dp)

2017-07-24 10:32 169 查看

描述

某个夜晚,Bob将他弹奏的钢琴曲录下来发给Jack,Jack感动之余决定用吉他为他伴奏。

我们可以用一个整数表示一个音符的音高,并可认为Bob弹奏的曲子是由3N个整数构成的一个序列。其中每个整数的取值范围是[-200, 200]。

Jack共弹奏 N 个和弦,每个和弦由三个音符组成。Jack可以自行决定和弦的第一个音符,其后的两个音符由第一个音符与和弦种类所决定。Jack共弹奏两种和弦:大三和弦与小三和弦。假设Jack决定某个和弦的第一个音符是 x,那么对于大三和弦,余下两个音符依序是 x+4和 x+7;对于小三和弦,余下两个音符依序是x+3和x+7。两个和弦相同,当且仅当其对应位置的三个音符都相同。其中每个和弦的第一个音符x的取值范围也是[-200, 200]。

Jack很懒,一旦决定弹奏某个和弦后,便不愿意更换和弦。即如果他开始弹奏1,5,8这个和弦,他将不停重复1,5,8,1,5,8,1,5,8……Bob觉得这样过于单调,于是Jack妥协:他表示愿意更换和弦,但最多更换K次。最开始选择和弦不计在更换次数内。

我们用不和谐值衡量乐曲与伴奏之间的契合程度。记某时刻Bob弹奏音符的音高为a,Jack弹奏音符的音高为b,则该点的不和谐值为|a-b|。整首乐曲的不和谐值等于这3N个不和谐值之和。

Jack希望选取最美的一组和弦,使得整首乐曲的不和谐值达到最小。你需要输出这个最小值。

输入

第一行两个正整数 N (≤1000), K (≤20).

第二行3N个整数(取值范围[-200, 200])为Bob的曲谱。

输出

一个整数,为乐曲最小不和谐值。

样例输入

3 1
-1 3 6 4 7 11 21 26 28


样例输出

15


思路

基础的
dp
问题。

我们设
dp[i][j][s][k]
代表第
i
个和弦,在已经更换
j
次的情况下,使用
s
和弦,起始音符为
k
时所得到的最小不和谐值。

对于每一个新的和弦,我们可以选择更换或者不更换当前正在演奏的和弦。

于是便有状态转移方程:

dp[i][j][s][k]=min(val[j−1],dp[i−1][j][s][k])+getsum(i,k,s)

其中
val[j-1]
代表更换
j-1
次和弦所得到的最小不和谐值,它也就等于
dp[i-1][j-1][0~1][-200~200]
中的最小值。

getsum
代表选择
s
和弦,
k
为起始音符所计算的不和谐值。

AC 代码

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define inf 0x3f3f3f

int a[1005][3];
int dp[1005][25][2][405];
int val[25];

inline int getsum(int i,int k,int s)
{
return abs(k-a[i][0])+abs(k+3+s-a[i][1])+abs(k+7-a[i][2]);
}

int main()
{
int n,ks;
while(~scanf("%d%d",&n,&ks))
{
for(int i=0; i<n; i++)
for(int j=0; j<3; j++)
scanf("%d",&a[i][j]);
for(int i=0; i<n; i++)
{
for(int k=-200; k<=200; k++)
{
for(int l=0; l<=ks; l++)
{
for(int s=0; s<2; s++)
{
dp[i][l][s][k+200]=dp[max(i-1,0)][l][s][k+200]+getsum(i,k,s);
if(l)dp[i][l][s][k+200]=min(val[l-1]+getsum(i,k,s),dp[i][l][s][k+200]);
}
}
}
memset(val,inf,sizeof(val));
for(int k=-200; k<=200; k++)
for(int l=0; l<=ks; l++)
val[l]=min(val[l],min(dp[i][l][0][k+200],dp[i][l][1][k+200]));
}
printf("%d\n",val[ks]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: