复杂DP(蓝桥)

复杂DP

1.鸣人的影分身

题目:

影分身是由鸣人身体的查克拉能量制造的,使用的查克拉越多,制造出的影分身越强。

针对不同的作战情况,鸣人可以选择制造出各种强度的影分身,有的用来佯攻,有的用来发起致命一击。那么问题来了,假设鸣人的查克拉能量为 M,他影分身的个数最多为 N,那么制造影分身时有多少种不同的分配方法?

  1. 影分身可以分配0点能量。
  2. 分配方案不考虑顺序,例如:M=7,N=3那么 (2,2,3) 和 (2,3,2) 被视为同一种方案。

思路:

首先这道题是一道选择问题,N个人每个人选多少要满足要求和为M。且每个人可以为0。可以想到这和背包问题很像。那么我们可以定义集合:f(i,j)表示所有总和是i的且分成j个数的方案数。那么分类的依据可以是这一组的最后一个数是否为0。

初始化f(0,0)代表总和为0分成0个数的方案,是一种

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QAApixUz-1584572906821)(C:\Users\15209\Pictures\博客\dp001.jpg)]

代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int N=11;
int f[N][N] ;//所有总和是i且分成j个数的方案

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int m,n;
        cin>>m>>n;
        f[0][0]=1;
        for(int i=0;i<=m;i++)
            for(int j=1;j<=n;j++)
            {
                f[i][j]=f[i][j-1];
                if(i>=j) f[i][j]+=f[i-j][j];
            }
            
        printf("%d\n",f[m][n]);
    }
    return 0;
}

2.糖果

题意:

dzx可以从N件产品中选任意若干件带回家,N件产品每件都包含数量不同的糖果,dzx选的糖果总数必须是K的整数倍,在满足条件的基础上,糖果数越多越好。

在这里插入图片描述

思路:

这题也是一道选择问题,每一种糖果我们都可以选和不选,因此可以根据第i个糖果选和不选来分类,我们可以定义f(i,j)为:我们从前i中糖果中选,总和除去k余j的糖果的最大值。

代码:

#include <cstdio>
#include <cstring>

int max(int a,int b)
{
    return a>b?a:b;
}

const int N=110;
int f[N][N];

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    
    memset(f,-0x3f,sizeof f);
    f[0][0]=0;
    
    for(int i=1;i<=n;i++)
    {
        int w;
        scanf("%d",&w);
        for(int j=0;j<=k;j++)
            f[i][j]=max(f[i-1][j],f[i-1][(j+k-w%k)%k]+w);
    }
    
    printf("%d\n",f[n][0]);
    
    return 0;
    
}

3.密码脱落

题意:

给定一个字符串,求最少插入多少个字母能将它变成回文串。字符串长度不超过1000。

思路:

我们可以想到可以先求原字符串的最长子回文串,最后剩下的多余的就是我们要加入和他们匹配的,所以最后答案就是字符串长度-最长回文子串。那么我们现在要求的就是给定字符串中的最长回文子串。我们可以定义f(l,r):l到r这段区间中的最长回文子串。区间的分类问题一般根据端点来分,可以分成四类。只需要求最大值即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MJpDvlSk-1584572906826)(C:\Users\15209\Pictures\博客\dp003.jpg)]

代码:

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

using namespace std;
const int N=1010;

char str[N];
int f[N][N];//l,r之间最长的回文串长度

int main()
{
    cin>>str;
    int n =strlen(str);
    
    for(int len=1;len<=n;len++)
        for(int l=0;l+len-1<n;l++)
        {
            int r=l+len-1;
            if(len==1) f[l][r]=1;
            else 
            {
                if(str[l]==str[r]) f[l][r]=f[l+1][r-1]+2;
                if(f[l+1][r]>f[l][r]) f[l][r]=f[l+1][r];
                if(f[l][r-1]>f[l][r]) f[l][r]=f[l][r-1];
            }
            
        }
        
    cout<<n-f[0][n-1];
    
    return 0;
    
}
发布了75 篇原创文章 · 获赞 8 · 访问量 1252

猜你喜欢

转载自blog.csdn.net/qq_40905284/article/details/104959196