uva 1291 dp

UVA 1291 - Dance Dance Revolution

有一个跳舞机。原点为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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值