[2020年牛客算法入门课练习赛2] 古老的牛市,遗迹的天梯

古老的牛市,遗迹的天梯

题解:这个台阶的题一看受制于前面台阶的影响,并且不同的选择都有可能造成最优结果,不像贪心那样“单纯”,那么很可能用动态规划去搞。
那么状态如何定义?状态如何转移?成为解决动态规划的关键。
由于本题题目信息不复杂,无非上下台阶问题,所以很容易想到状态表示。
dp[i]:到第i个台阶至少需要多少步。
第i个台阶无非由两种状态转移

  1. 由第i-1台阶直接走到,如果h[i-1]+1==h[i],那么dp[i]=dp[i-1]+1
  2. 由前一部分第j个台阶跳跃得到,那么问题来了,前一部分第j个台阶指的是哪些台阶?
    由题意可知 h [ j ] + 2 k h [ i ] ( j + k < i ) {h[j]+2^k≥h[i] (j+k<i) } ,此时的k取符合前面的条件所有k中的最小值,那么可以通过数学方法或者枚举得到最小k,由于枚举复杂度不大,所以在此我用枚举解决。
    得到k后,dp[i]=dp[j+k]+k+1

知道了状态以及转移方程,这道题可以说基本解决了。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>

const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=1e4+10;
const int maxm=105;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

ll h[205];
ll dp[205];
int main()
{
	int n;
	cin >> n;
	for(int i=1;i<=n;i++) cin >> h[i];
	memset(dp, inf, sizeof(dp));
	dp[1]=0;
	for(int i=2;i<=n;i++)
	{
		if(h[i]==h[i-1]+1) dp[i]=dp[i-1]+1;
		for(int j=1;j<i;j++)
		{
			ll k=inf;
			for(int l=0;;l++)
			{
				if(h[j]+(ll)pow(2, l)>=h[i])
				{
					k=l;
					break;
				}
			}
			if(j+k<=i-1) dp[i]=min(dp[i],dp[j+k]+k+1);
		}
	}
	if(dp[n]==inf) cout << -1;
	else cout << dp[n] << endl;
}

猜你喜欢

转载自blog.csdn.net/weixin_44235989/article/details/106773092