思路
首先将乐谱抽象为一个序列(note_id,Vol),表示以Vol的音量按了钢琴上编号为note_id的琴键。注意这个note_id应该用唯一的编号。
将问题分为两部分:音量代价与音符代价。这两部分的代价计算是分开的。
音量代价:只有在按音符时音量与当前音量不同时计算代价。注意默认音量是100。
音符代价:可以使用动态规划计算。dp[x][y]表示按完前x个音符,当前音阶为y的最小代价。直接按照题目所给信息转移即可。也可以使用最短路。
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int f[15],l,x,y,z,t,p,q,r,k;
char s[100005];
int calc()
{
t=1;
int r=0;
while(isdigit(s[k+1])&&k+1<=l)
(r*=10)+=s[++k]-48,t++;
return r;
}
int main()
{
while(scanf("%s",s+1)&&s[1]!='*')
{
l=strlen(s+1);
x=100;
y=4;
z=100;
for(int i=1;i<=8;i++)
f[i]=2;
f[4]=0;
f[3]=f[5]=1;
for(k=1;k<=l;k++)
{
if(s[k]=='V')
x=calc();
else if(s[k]=='O')
y=s[++k]-48;
else if(s[k]=='<')
y--;
else
if(s[k]=='>')
y++;
else
{
if(x!=z)
for(int i=1;i<=8;i++)
f[i]+=t;
z=x;
t=0;
p=s[k]-'A';
if(s[k+1]=='-')
k++,q=0;
else if(s[k+1]=='+')
k++,q=1;
else
q=-1;
if((p==4&&q==1)||(p==5&&q==0))
q=-1;
for(int i=1;i<=8;i++)
{
if(i==y)
f[i]+=1+(q!=-1);
else if(i==y+1&&p==1&&q)
f[i]+=1+(q==-1);
else if(i==y-1&&p==2&&q!=1)
f[i]+=1+(q==-1);
else
f[i]=inf;
}
}
for(int i=1;i<=8;i++)
{
for(int j=1;j<=8;j++)
{
if(abs(i-j)==1)
f[j]=min(f[j],f[i]+1);
else
f[j]=min(f[j],f[i]+2);
}
}
}
r=inf;
for(int i=1;i<=8;i++)
r=min(r,f[i]);
printf("%d\n",r);
}
return 0;
}
来源:zr