题目:
Description
一个游戏,在屏幕上有5个格子形成一行,每一秒都会有一个格子闪烁,格子闪烁时你需要保证至少有一只手指在格子上面, 现在我们已经知道第i秒时,第xi个格子会闪烁,我们假设手指的移动不花费时间,你现在用两根手指玩这个游戏, 设初始两根手指都在0处位置,算出n秒过后手指需要移动的最小距离。(允许手指交叉)
注:手指移动的距离的计算是,假设你的一根从x,移动到y格,那么移动的距离是|x-y|
Input
第一行一个数T,表示有T组测试数据(T<=50) 第二行,n,表示进行n秒(1<=n<=10^4) 下一行 n个数,xi(0<=xi<=4)
Output
输出n秒过后手指需要移动的最小距离.
Sample Input
1202
Sample Output
2
思路:
DP~
dp[i][j][k] 指的是左指在位置i,右指在位置j时第k秒移动的最小距离.
dp[a[k]][j][k] = min(dp[a[k]][j][k], dp[i][j][k-1]+abs(i-a[k]));
dp[i][a[k]][k] = min(dp[i][a[k]][k], dp[i][j][k-1]+abs(j-a[k]));
AC.
思路:
DP~
dp[i][j][k] 指的是左指在位置i,右指在位置j时第k秒移动的最小距离.
dp[a[k]][j][k] = min(dp[a[k]][j][k], dp[i][j][k-1]+abs(i-a[k]));
dp[i][a[k]][k] = min(dp[i][a[k]][k], dp[i][j][k-1]+abs(j-a[k]));
AC.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 10005;
int a[maxn], dp[5][5][maxn];
int abs(int x)
{
if(x<0) return -x;
return x;
}
int main()
{
//freopen("in", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
memset(a, 0, sizeof(a));
memset(dp, 0x3f, sizeof(dp));
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
dp[0][0][0] = 0;
for(int k = 1; k <= n; ++k) {
for(int i = 0; i < 5; ++i) {
for(int j = 0; j < 5; ++j) {
dp[a[k]][j][k] = min(dp[a[k]][j][k], dp[i][j][k-1]+abs(i-a[k]));
dp[i][a[k]][k] = min(dp[i][a[k]][k], dp[i][j][k-1]+abs(j-a[k]));
}
}
}
int ans = maxn;
for(int i = 0; i < 5; ++i) {
for(int j = 0; j < 5; ++j) {
ans = min(ans, dp[i][j][n]);
}
}
printf("%d\n", ans);
}
return 0;
}