一、动态规划
近来做动态规划的题的新发现
①一般流程:确定子问题,定义状态,转移方程,避免重复计算
②递推求出的是数据,所以只是针对数据进行操作;而动态规划求出的是最优状态,所以必然也是针对状态的操作,而状态自然可以出现在最优解中,也可以不出现——这便是决策的特性(布尔性)。
③画图是一般动态规划题的必要操作
二、合唱队形


1.思路
这道题其实就是求上升子序列,下降子序列,从左边开始就是最大上升子序列(单调递增),从右边开始就是最大下降子序列(单调递减)
从右到左
for(i=n-1;i>=1;i--)
{
for(j=i+1;j<=n;j++)if(a[i]>a[j]&&num1[i]<=num1[j]+1)
num1[i]=num1[j]+1;
}
由此我们可以画图来理解这个过程

上面蓝色代表的就是num1,表示上升子序列的长度
那么从左到右的就是

那么接下来把他们合在一起就行了
2.代码实现
#include<stdio.h>
int n;
int a[101],num1[101],num2[101],dp[101];
int max(int x,int y)
{
if(x>y)return x;
else return y;
}
int main()
{
int i,j,maxx=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
num1[i]=1;
num2[i]=1;
scanf("%d",&a[i]);
}
for(i=n-1;i>=1;i--) //从右到左
{
for(j=i+1;j<=n;j++)if(a[i]>a[j]&&num1[i]<=num1[j]+1)
num1[i]=num1[j]+1;
}
for(i=2;i<=n;i++) //从左到右
{
for(j=1;j<i;j++)if(a[i]>a[j]&&num2[i]<=num2[j]+1)
num2[i]=num2[j]+1;
}
for(i=1;i<=n;i++) //合在一起,找最大
{
dp[i]=num1[i]+num2[i]-1;
maxx=max(maxx,dp[i]);
}
printf("%d",n-maxx);
return 0;
}
三、摆花



1.思路
首先我们先定义一个二维数组dp,那么dp[i][j]种的i表示摆的第i种花,j表示摆的盆数,其中我们其中我们还要设置一个k,代表已经摆来的盆数,那么状态转移方程就为dp[i][j+k]+=dp[i-1][k];
2.代码实现
#include<stdio.h>
int n,m;
int dp[101][101],a[101];
int main()
{
int i,j,k;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=0;i<=n;i++)dp[i][0]=1;
for(i=1;i<=n;i++)
{
for(j=0;j<=a[i];j++)
{
for(k=0;k<=m-j;k++)
{
if(j==0&&k==0)continue;
dp[i][j+k]+=dp[i-1][k];
dp[i][j+k]%=1000007;
}
}
}
printf("%d",dp[n][m]);
return 0;
}