动态规划

数塔

dp[i][j] = max(dp[i+1][j],dp[i+1][j+1])+f[i][j];

最大连续子序列和

dp[i]记录以A[i]为末尾的连续序列最大和。
状态转移方程:dp[i] = max{A[i], dp[i-1]+A[i]}

#include<stdio.h>
int n,data[1010],dp[1010];
int main(){
    while(scanf("%d",&n)!=EOF){
        for(int i=0;i<n;i++){
            scanf("%d",&data[i]);
        }
        dp[0] = data[0];
        int ans=-1;
        for(int i=0;i<n;i++){
            if(dp[i-1]+data[i]>data[i]){
                dp[i] = dp[i-1]+data[i];
            }
            else{
                dp[i] = data[i];
            }
            if(dp[i]>ans)
                ans = dp[i];
        }
        printf("%d\n",ans);

    }
    return 0;
}

最长不下降子序列

dp[i]表示以A[i]结尾的最长不下降子序列长度。
状态转移方程
dp[i] = max{1,dp[j]+1} (j=1,2,…,i-1&&A[j]<A[i])
边界:dp[i] = 1(1<=i<=n)

#include<stdio.h>
#include<string.h>
int main(){
    int A[100],l;//n记录数组长度,A[n]记录数据
    int dp[100] = {0};
    while(scanf("%d",&l)!=EOF){
        for(int i=0;i<l;i++){
            scanf("%d",&A[i]);
        }
        int ans=-1;
        for(int i=0;i<l;i++){
            dp[i]=1;
            for(int j=0;j<i;j++){
                if(A[i]>=A[j]&&dp[i]<dp[j]+1){
                    dp[i] = dp[j] + 1;
                    if(dp[i]>ans){
                        ans=dp[i];
                    }
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

最长公共子序列

dp[i][j]记录字符串A的i号位和字符串B的j号位之前的LCS长度
(注意解法中特殊的输入技巧

状态转移方程:  
			dp[i-1][j-1] + 1;A[i]==B[j]		
			//A,B串不同i-1,j-1
dp[i][j] = 
			max{dp[i-1][j],dp[i][j-1]};A[i]!=B[j]			

边界:dp[i][0] = dp[0][j] = 0 (0<=i<=n,0<=j<=m)
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[100][100];
char A[100],B[100];
int main(){
    while(scanf("%s%s",A+1,B+1)!=EOF){//特殊技巧A+1 从第1个元素开始读取
        int l1=strlen(A+1),l2=strlen(B+1);//计算长度时也从1开始 所以要循环到length才可
        for(int i=0;i<=l1;i++)
            dp[i][0] = 0;
        for(int j=0;j<=l2;j++)
            dp[0][j] = 0;
        for(int i=1;i<=l1;i++){
            for(int j=1;j<=l2;j++){
                if(A[i]==B[j])
                    dp[i][j] = dp[i-1][j-1] + 1;
                else{
                    dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        printf("%s %s %d\n",A+1,B+1,dp[l1][l2]);

    }
    return 0;
}

最长回文子串

dp[i][j]表示s[i]至s[j]所表示的串是否为回文串,是则为1不是则为0。

状态转移方程:
			dp[i+1][j-1],s[i]==s[j]
			//满足看子串
dp[i][j] = 
			0,s[i]!=s[j]
边界: dp[i][i] = 1,dp[i][i+1] = (s[i] == s[i+1])?1:0;

特殊递归写法:
按子串长度和子串初始位置进行枚举,及第一遍求长度为3的子串,第二遍求长度为4的子串。。。

//s为串
int len = strlen(s),ans=1;
memset(dp,0,sizeof(dp));//dp数组初始化为0
//边界
for(int i=0;i<n;i++){
	dp[i][i] = 1;
	if(i<len-1){
		if(s[i]==s[i+1]){
			dp[i][i+1] = 1;
			ans = 2;
		}
	}
}
//状态转移方程
for(int L=3;L<=len;L++){//枚举子串长度
	for(int i=0;i+L-1<len;i++){//枚举子串的起始端点
		int j=i+L-1;//子串的右端点
		if(s[i] == s[j] && dp[i+1][j-1] == 1){
			dp[i][j] = 1;
			ans = L;
		}
	}
	cout<<ans<<endl;
}

或者

#include<stdio.h>
#include<string.h>
int dp[100][100];
int main(){
    char str[100];
    int len,ans;
    memset(dp,0,sizeof(dp));
    while(scanf("%s",str)!=EOF){
        len = strlen(str);
        for(int i=0;i<len;i++){
            dp[i][i]=1;
            ans=1;
        }
        for(int i=0;i<len-1;i++){
            if(str[i]==str[i+1]){
                dp[i][i+1] = 1;
                ans=2;
            }
            else{
                dp[i][i+1] = 0;
            }
        }
        for(int l=3;l<=len;l++){
            for(int i=0;i+l-1<len;i++){
                int j=i+l-1;
                if(str[i]==str[j]&&dp[i+1][j-1]==1){
                    dp[i][j] = 1;
                    ans = l;
                }
                else{
                    dp[i][j] = 0;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

背包

有一个容量为v的背包和一些物品。这些物品分别有两个属性,体积为w和价值为v。要求用这个背包装下价值尽可能多的物品,求其最大价值。

01背包问题(有穷件

dp[i][j]表示总体积不超过j的情况下,前i个物品能达到的最大价值。
状态转移方程:
dp[i][v] = max{dp[i-1][v],dp[i-1][v-w[i]]+c[i]};
//max(不装入该物品所能达到的最大价值,装入该物品所能达到的最大价值);
特别注意判断v-w[i]是否为负,若是,则不能被转移。
边界:dp[0][v] = 0;(0<=v<=V)
注意:每个状态只和上一个状态有关,特别进行空间优化

dp[v] = max{dp[v],dp[v-w[i]]+c[i]}
变为一维数组后,为了保证使用数据不变(该物品只能被取一次,枚举方向必须逆序
代码如下:

#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=100;
int dp[maxn];
struct thing{
    int u;//体积
    int w;//质量
};
thing t[maxn];
int main(){
    int data[maxn];
    int v,n;//n为数组长度
    while(scanf("%d%d",&n,&v)!=EOF){
        for(int i=0;i<n;i++){
            scanf("%d%d",&t[i].u,&t[i].w);
        }
        for(int i=0;i<v;i++){
            dp[i] = 0;
        }
        for(int i=0;i<n;i++){
            for(int j=v;j>=t[i].u;j--){
                dp[j] = max(dp[j],dp[j-t[i].u]+t[i].w);
            }
        }
        printf("%d\n",dp[v]);
    }
    return 0;
}

形成自己的解题风格
struct thing{
int v;
int w;
}
记录物品信息
0-1背包变化问题: 所选择的物品必须恰好装满背包
此时dp[i][j]必须保证体积和为j
解决方法:
改变初始状态
初始状态变为dp[0][0]为0,而其他dp[0][j]均变为负无穷。

理由如下:(观看某大神解
由f[j]=Math.max(f[j],f[j-w[i]]+v[i])知,第i步的最优解都是根据第i-1步推得,要想第i步获得的结果恰好装满,那么第i-1步也必须是恰好装满的最优解,否则第i-1的解也应该为Integer.minValue,因为Integer.minValue+W[i]=Integer.minValue。

完全背包(无穷件

状态转移方程:
dp[i][v] = max(dp[i-1][v],dp[i][v-w[i]]+c[i]);
边界:dp[0][v] = 0;
改成一维形式:
dp[v] = max(dp[v],dp[v-w[i]]+c[i]);
边界:dp[v] = 0;
此时有无穷件可取,所以正向枚举即可

for(int i=1;i<=n;i++{
	for(int v=w[i];v<=V;v++){
		dp[v] = max(dp[v],dp[v-w[i]]+c[i]);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值