题目大意:一个跳舞机,分上下左右中,中编号是0,然后从上开始逆时钟编号1、2、3、4,有一串你要踩的序列,从0到周围4个,花费为2,周围两个相邻的动一下是3,跳到对面去是4,同一格踩一下是1,两个脚不能同时踩在同一格,问你这串序列踩完最少的花费。
思路:动态规划的思想应该挺明确的,思路也挺清晰地,设d[ i ][ j ][ k ] 表示踩完第i个,左脚在i号位置,右脚在j号位置的最小值,状态转移方程为d[ i ][ pos ][ k ] = min(d[ i-1 ][ a ][ k ] + cost[a,pos]),d[ i ][ j ][ pos ] = min( d[ i -1 ][ j ][ a ] + cost[a,pos]) ,pos为第i个应踩的位置,前者为左脚踩过来,后面是右脚。
由于没告诉范围,掀开始我就开了个10^6的dp数组,可是一直都是TLE,感觉不会超时,然后看了下别人的,他们都是用滚动数组的,我改了一下,一交,马上AC。。 之后我把前面TLE那个改为10^5的数组,AC了,后来一看,果然是 memset 初始化的问题。。。感觉以后那种数组范围不确定的时候还是用滚动数组好一点。。 = =
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF = 0x0fffffff ;
int cost[5][5];
void init()
{
for(int i = 1;i<=4;i++)
{
cost[0][i] = cost[i][0] = 2;
cost[i][i] = 1;
}
cost[0][0] = 1;
for(int i =1;i<=3;i++)
cost[i][i+1] = cost[i+1][i] = 3;
cost[1][4] = cost[4][1] = 3;
cost[1][3] = cost[3][1] = 4;
cost[2][4] = cost[4][2] = 4;
}
int d[2][5][5];
int main()
{
init();
int a;
while(~scanf("%d",&a)&&a)
{
memset(d[0],0x7f,sizeof(d[0]));
d[0][a][0] = d[0][0][a] = 2;
int pre = 0;
int cur ;
while(scanf("%d",&a)&&a)
{
cur = pre^1;
memset(d[cur],0x7f,sizeof(d[cur]));
for(int j = 0;j<=4;j++)
for(int k = 0;k<=4;k++)
d[cur][a][j] = min(d[pre][k][j] + cost[a][k],d[cur][a][j]);
for(int j = 0;j<=4;j++)
for(int k = 0;k<=4;k++)
d[cur][j][a] = min(d[pre][j][k] + cost[a][k],d[cur][j][a]);
pre = cur;
}
int ans = INF;
for(int i = 0;i<=4;i++)
for(int j = 0;j<=4;j++)
{
if(i==j) continue;
ans = min(d[cur][i][j],ans);
}
printf("%d\n",ans);
}
return 0;
}