古老的牛市,遗迹的天梯
题解:这个台阶的题一看受制于前面台阶的影响,并且不同的选择都有可能造成最优结果,不像贪心那样“单纯”,那么很可能用动态规划去搞。
那么状态如何定义?状态如何转移?成为解决动态规划的关键。
由于本题题目信息不复杂,无非上下台阶问题,所以很容易想到状态表示。
dp[i]:到第i个台阶至少需要多少步。
第i个台阶无非由两种状态转移
- 由第i-1台阶直接走到,如果h[i-1]+1==h[i],那么dp[i]=dp[i-1]+1
- 由前一部分第j个台阶跳跃得到,那么问题来了,前一部分第j个台阶指的是哪些台阶?
由题意可知 ,此时的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;
}