UVA 1291 - Dance Dance Revolution
dp[i][j]表示跳到第i个数字的时候那只不确定的脚的位置是j的时候所消耗能量的最小值。那么跳第i+1个数字的时候可以由两只脚(a[i], j)跳过去,将会有两种结果(a[i+1], j) 和(a[i+1], a[i])。得到两个状态dp[i+1][j], dp[i+1][a[i]]。
dp[i+1][j] = dp[i+1][j] + _get(a[i], a[i+1]);
dp[i+1][a[i]] = dp[i+1][j] + _get(j, a[i+1]);
_get(a, b) 求出a跳到b所消耗的能量。其实就是几个特判。
有一个跳舞机。原点为0,有四个方向,上左下右,分别标成(1234),初始玩家两只脚站在 0 位置,跳舞机会给出一串数字,玩家要按照顺序踩下四个方向的数字。移动脚会消耗玩家的能量,从0位置移动到四个方向消耗2点能量,从一个方向移动到另一个相邻的方向消耗3点能量,从一个方向移动到相反方向消耗4点能量,原点踩一下消耗1点能量。问你踩出这串数子最少要花多少能量。
根据能量消耗关系,我们可以发现当前两只脚踩的方向才是重点。然而要记录两只脚的方向么?其实不用,因为我们可以发现两只脚的状态是互不影响的,而且单跳到第i个数字的时候,有一只脚的位置是确定的。
dp[i][j]表示跳到第i个数字的时候那只不确定的脚的位置是j的时候所消耗能量的最小值。那么跳第i+1个数字的时候可以由两只脚(a[i], j)跳过去,将会有两种结果(a[i+1], j) 和(a[i+1], a[i])。得到两个状态dp[i+1][j], dp[i+1][a[i]]。
dp[i+1][j] = dp[i+1][j] + _get(a[i], a[i+1]);
dp[i+1][a[i]] = dp[i+1][j] + _get(j, a[i+1]);
_get(a, b) 求出a跳到b所消耗的能量。其实就是几个特判。
然后在dp[n][*]里面找个最小值。
#include <bits/stdc++.h>
using namespace std;
const int INF = 999999999;
int k;
int a[100010];
int _read() {
int tmp;
for ( k=1; scanf("%d", &tmp) && tmp; ) {// cout << tmp << endl;
a[k++] = tmp;
}
// a[k++] = tmp;
return k;
}
int dp[100010][5];
int _get(int a, int b) {
if (a == 0) return 2;
if (a == b) return 1;
if (abs(a-b) == 1 || abs(a-b) == 3) return 3;
if (abs(a-b) == 2) return 4;
}
int main () {// cout << "*" << endl;
for (; _read() != 1; ) {// cout << k << endl;
for (int i=0; i<=k; i++) {
fill(dp[i], dp[i]+5, INF);
}
dp[1][0] = _get(0, a[1]);
for (int i=2; i<k; i++) {
for (int j=0; j<=4; j++) {
dp[i][j] = min(dp[i][j], dp[i-1][j] + _get(a[i-1], a[i]));
dp[i][a[i-1]] = min(dp[i][a[i-1]], dp[i-1][j] + _get(j, a[i]));
}
}
int ans = INF;
for (int i=0; i<=4; i++) {
ans = min(ans, dp[k-1][i]);
}
printf("%d\n", ans);
}
return 0;
}