一、定义
在多阶段决策的问题中,各阶段采取的决策,一般俩说是与空间或者时间相关的。决策依赖于当前状态,又随即引起状态的转移,一个决策序列就是在变化的状态中产生出来,故有动态的含义。
我们称这种解决多阶段决策最优化的过程称为动态规划方法。
例如在一个m*n的迷宫中,从左下角走到右上角
可以看到,状态A和状态B应当属于同一个阶段。T可以从A走来,也可以从B走来,故dp[T]=min(dp[A]+map[A][T],dp[B]+map[B][T]);即终点的最短路应当是A或者B的最短路+最后一段长度.
动态规划的几个术语:
阶段:把所求问题的过程按照时间或者空间恰当地划分成若干个相互联系的阶段。
状态:表示每个阶段的客观状态,它既是每个阶段的出发位置,又是前一阶段的终点。
无后效性:如果给定某一阶段的状态,则在这一阶段以后的过程发展不受这个阶段以前的各个状态的影响,所以各阶段确定了,整个过程也就确定了。
决策:一个阶段的状态给定之后,从该状态演变到下一状态的一种选择。
策略:每个阶段决策组成的序列。
最优性原理:把一个大问题划分成多个子问题,对于整个问题必须最优的情况时,子问题也必须最优,即问题具备最优子结构的性质。
二、线性dp
线性动态规划中状态是一维的,第i个元素的状态与前i-1个元素的状态有关,前i-1个状态组成一个决策序列,它是其他类动态规划的基础。
合唱队形
题目描述: N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学不交换位置就能排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1, 2, …, K,他们的身高分别为T1, T2, …, TK, 则他们的身高满足T1 < T2 < … < Ti , Ti > Ti+1 > … > TK (1 <= i <= K)。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入: 输入的第一行是一个整数N(2 <= N <= 100),表示同学的总数。 第一行有n个整数,用空格分隔,第i个整数Ti(130 <= Ti <= 230)是第i位同学的身高(厘米)。
输出: 可能包括多组测试数据,对于每组数据,输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
样例输入:
8
186 186 150 200 160 130 197 220
分别求出从左往右最长递增序列,从右往左最长递增序列(即从左往右递减)。
计算每一个位置作为中点的时候,队伍能达到的长度,取最长
注意求从左往右递减的时候,需要从n-1开始遍历,否则不满足无后效性的条件
#include<iostream>
using namespace std;
int a[110],in[110],de[110];
int main()
{
int i,j,n;
cin>>n;
for(i=1;i<=n;i++)
{
cin>>a[i];
in[i]=de[i]=1;
}
for(i=1;i<=n;i++)//从左向右找递增
{
for(j=i-1;j>=1;j--)
{
if(a[i]>a[j]&&in[i]<in[j]+1)
in[i]=in[j]+1;
}
}
for(i=n;i>=1;i--)//从右向左找递减
{
for(j=i+1;j<=n;j++)
{
if(a[i]>a[j]&&de[i]<de[j]+1)
de[i]=de[j]+1;
}
}
int ma=0;
for(i=1;i<=n;i++)
if(ma<in[i]+de[i]-1)
ma=in[i]+de[i]-1;
printf("%d",n-ma);
return 0;
}