Mortal Kombat Tower (dp动态规划)

题意

A和B两人玩通关游戏,每个关卡分为难(a[i]=1)和简单(a[i]=0),A可以通过任意难度的关卡,B只能通过难度为0的关卡,但是B在遇到难度为1的关卡的时候,可以选择跳跃一次,A和B轮流交替通关,每一轮两人最少可以通关一关,最多通关两关,B始终第一个开始,问:最终通关时,B进行跳跃的最少次数

题目传传送门:点击进入

思路

由于是需要求一个最优解,同时这个最优解由AB两人的选择控制,为了维护这个结果最优,需要每个回合两人的选择都是最优的,同时A的选择还会影响到B的选择。所以我们考虑动态规划进行求解。

求解动态规划的四个步骤

一、确定状态

设数组dp[i][0]表示第i轮中 B消耗的跳跃次数, dp[i][1]表示第i轮中,A消耗的跳跃次数。

两个意识:

1.最后一步

即最终的一个状态。本题中的最后一个状态应该是min( dp[n][0], dp[n][1] )

2.子问题

由于我们的每一轮的最终答案是由上一轮的结果来决定,所以我们可以将每个问题化解成它的子问题,在本题中,我们考虑走到最后一关的最优解,则可以将问题拆解为最后一关的最优解+前面通过的所有关卡的最优解,不断拆分,就可以将问题简化为我们已知的问题。

二、 状态转移方程

对于dp问题,最关键的就是推出该问题的状态转移方程,在本题中,我们设数组dp[i][0]表示第i轮中 B消耗的跳跃次数,
dp[i][1]表示第i轮中,A消耗的跳跃次数。由于AB两人在自己的回合可以选择通过1关或者2关,所以我们需要每一轮都选择二者中消耗跳跃步数最少的一个决策,以确保最后的决策是最优的。

对于第i回合的B来说:
选择通1关:
dp[i][0] = dp[i-1][1] + a[i];

选择通2关:因为是通两关,所以要加上a[i-1]和当前的关卡a[i]
dp[i][0] = dp[i-2][1] + a[i-1] + a[i]

第i轮B的最优策略为:dp[i][0] = min( dp[i-1][1] + a[i],dp[i-2][1] + a[i-1] + a[i] )

对于第i回合的A来说
选择通1关:

dp[i][1] = dp[i-1][0]

选择通2关:

dp[i][1] = dp[i-2][0]

第i轮A的最优策略为:dp[i][1] = min( dp[i-1][0], dp[i-2][0])

三、初始条件和边界情况

边界情况在本题中不需要考虑。初始条件为:

第一轮:dp[1][0] = a[1] dp[1][1] = 无限大(因为B始终走第一轮)

第二轮:dp[2][0] = a[1] + a[2] dp[2][1] = dp[1][0]

四、计算顺序

一般来说按照从小到大,从左往右,或者对于二维数组来说一行一行的进行计算。

AC代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <math.h>
#include <set>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 2e5 + 5;
typedef long long ll;
const int INF = 0x3f3f3f3f;
int a[maxn];
int dp[maxn][2];
int main() {
	int t = 0;
	cin >> t;
	while(t--){
		int n;
		cin >> n;
		for(int i = 1; i <= n; i++){
			cin >> a[i];
		}
		dp[1][0] = a[1];
		dp[1][1] = INF;

		dp[2][0] = a[1] + a[2];  //前两个数
		dp[2][1] = dp[1][0];

		for(int i = 3; i <= n; i++){
			dp[i][0] = min(dp[i-1][1] + a[i],dp[i-2][1] + a[i] + a[i-1] + a[i]);
			dp[i][1] = min(dp[i-1][0],dp[i-2][0]);
		}
		cout << min(dp[n][0],dp[n][1]) << endl; 
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值