codevs 3049 舞蹈家怀特先生
怀特先生是一个大胖子。他很喜欢玩跳舞机(Dance Dance Revolution, DDR),甚至希望有一天人家会脚踏“舞蹈家怀特先生”。可惜现在他的动作根本不能称作是在跳舞,尽管每次他都十分投入的表演。这也难怪,有他这样的体型,玩跳舞机是相当费劲的。因此,他希望写一个程序来安排舞步,让他跳起来轻松一些,至少不要每次都汗流浃背。
DDR的主要内容是用脚来踩踏板。踏板有四个方向的箭头,用1 (Up)、2 (Left)、3 (Down)、4 (Right)来代表,中间位置由0来代表。每首歌曲有一个箭头序列,游戏者必须按照或这个序列一次用某一只脚踩相应的踏板。在任何时候,两只脚都不能在同一踏板上,但可以同时待在中心位置0。
每一个时刻,它必须移动而且只能移动他的一只脚去踩相应的箭头,而另一只脚不许移动。跳完一首曲子之后,怀特先生会计算他所消耗的体力。从中心移动到任何一个箭头耗费2单位体力,从任何一个箭头移动到相邻箭头耗费3单位体力,移动到相对的箭头(1和3相对,2和4相对)耗费4单位体力,而留在原地再踩一下只需要1单位。怀特先生应该怎样移动他的双脚(即,对于每个箭头,选一只脚去踩它),才能用最少的体力完成一首给定的舞曲呢?
例如,对于箭头序列Left (2), Left (2), Up (1), Right (4),他应该分别用左、左、右、右脚去踩,总的体力耗费为2+1+2+3=8单位。
第一行N,表示有N个时刻 1<=N<=10000
第二到n+1行,每行一个数,表示需要踩得版
一个数,最小消耗体力
2
1
1
3
n<=10000
题解:
dp
f[i][j][k]表示第i次跳时,先生的左脚在j,右脚在k,则转移方程为
f[i][a[i]][k]=min{f[i-1][l][k]}
f[i][j][a[i]]=min{f[i-1][j][r]}
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,ans,f[10002][5][5],a[10002]; int dis(int u,int v){ if(u==v)return 1; if(u==0)return 2; int k=u-v; if(k==2||k==-2)return 4; return 3; } int main(){ scanf("%d",&n);ans=0x7ffffff; for(int i=1;i<=n;i++)scanf("%d",&a[i]); memset(f,0x3f,sizeof(f)); f[0][0][0]=0; for(int i=1;i<=n;i++) for(int j=0;j<=4;j++) for(int k=0;k<=4;k++){ f[i][j][a[i]]=min(f[i][j][a[i]],f[i-1][j][k]+dis(k,a[i])); f[i][a[i]][k]=min(f[i][a[i]][k],f[i-1][j][k]+dis(j,a[i])); } for(int i=0;i<=4;i++) for(int j=0;j<=4;j++) if(i!=j)ans=min(ans,f[n][i][j]); printf("%d\n",ans); return 0; }