学习总结(2.10)

一、动态规划

近来做动态规划的题的新发现

①一般流程:确定子问题,定义状态,转移方程,避免重复计算

②递推求出的是数据,所以只是针对数据进行操作;而动态规划求出的是最优状态,所以必然也是针对状态的操作,而状态自然可以出现在最优解中,也可以不出现——这便是决策的特性(布尔性)。

③画图是一般动态规划题的必要操作

二、合唱队形

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值