ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线性DP&背包DP

2022-01-24 20:00:36  阅读:90  来源: 互联网

标签:状态 背包 int max 线性 最优 DP


具有线性规划特点的DP类型称为线性DP
这类DP一般是较为基础的蒟蒻不提简单二字
DP:
状态表示应满足三个特点:
1.最优化:满足最优子结构性质
(略微不同于贪心的“滚雪球”,DP算法不一定满足局部最优导致全局最优,但DP算法可以通过更新最优解实现全局最优)
2.无后效性:即当前问题的决策不受后续决策的影响,这就是无后效性
比方说大佬翻身成为蒟蒻
3.子问题的重复性:应用DP的前提是子问题的相似性,这使得我们可以递推出来实现最优解的关系式:状态转移方程
所以,状态转移方程是DP算法实现的关键
线性DP:
线性DP的状态转移沿着维度有方向增长
下面DP典例:
1.LIS(最长上升子序列):显然如果有i,j使得i>j&&Ai>Aj,
那么Ai便可以添加到以Aj为结尾的上升子序列中,
与原以Ai结尾的上升子序列相比可得长度更长的更优,也就是状态更新
那么通过如上分析便可得到状态转移方程:
Bi=max(Bi,Bj+1),特殊的,B0=0
2.LCS(最长公共子序列)
这里我们用已处理过的部分和未处理过的部分相划分开
那么状态转移方程为:
F【i,j】=max(F【i-1,j】,F【i,j-1】,F【i-1,j-1】+1)
背包DP:原本背包9讲变7讲,我再吞3讲也没事吧
首先对于所有的背包DP来说,它们的状态转移方程统一,为:
F【j】=max(F【j】,F【j-v【i】】+w【i】)
其中i表示第i种物品对应价值w【i】,价格v【i】,j表示包内重量为j时所带来的最大价值为F【j】(上述价格与重量均表示为“代价”)
注释:在上述状态转移方程中:f【j-v【i】】毫无疑问是在包内质量位于j-v【i】时所获得最大值的状态,
此状态下加上w【i】表示假设如果在此状态下加上w【i】的值(显然w【i】对前一部分无影响,仍是理想下的最优状态),
与当前的最优状态比较,完成最大值的更新,最优状态的转移完成
1.0/1DP
N种物品,每种物品仅有1个,价值为C,价格为V,你所能付出的最大代价为M,
试求出不超过承受最大代价时所能收获的最大价值
套上述状态转移方程即可
Code

点击查看代码
void DP(){
    for(int i=1;i<=n;i++){//从第1种物品开始枚举到第n种物品
        for(int j=m;j>=v[i];j--){//0/1背包倒序查找防止出现某种物品重复使用
            f[j]=max(f[j],f[j-v[i]]+c[i]);//状态转移方程
        }
    }
    for(int i=1;i<=m;i++){//查找各种代价所得到的最优解
       ans=max(ans,f[i]);//用最优解更新答案
    }
    cout<<ans;//输出答案
    return;//结束,会了
}
2.完全背包 N种物品,每种无数个,价值C,价格V,最大承受代价M 仍问可承受范围内最大价值 还是一套状态转移方程,只不过循环结构适当变化 Code
点击查看代码
void DP(){
     for(int i=1;i<=n;i++){//从1到n遍历物品
         for(int j=v[i];j<=m;j++){//不同于0/1,这里正序循环保证可以使用无限件物品,当j的值从Ma变到Ma+v【i】时还可以使用i物品
             f[j]=max(f[j],f[j-v[i]]+c[j]);//状态转移更新
         }
     }
     for(int i=1;i<=m;i++){//遍历各种代价下的最优解
         ans=max(ans,f[i]);//更新答案
     }
     cout<<ans;//输出结果
     return;//结束
}
3.多重背包 N种物品,每种P个,价值C,价格V,最大承受M 我想说的是这里也有O(MN)算法
优化算法
#include <bits/stdc++.h>//单调队列维护多重背包
using namespace std;
int n,m,ans;
int v[501],w[501],c[501],f[6000];
int q[10000];
int calc(int i,int u,int k){
	return f[u+k*v[i]]-k*w[i];
}
int main(){
	cin>>n>>m;
	memset(f,0xcf,sizeof(f));
	f[0]=0;
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&v[i],&w[i],&c[i]);
		for(int u=0;u<v[i];u++){
			int l=1,r=0;
			int maxp=(m-u)/v[i];
			for(int k=maxp-1;k>=max(maxp-c[i],0);k--){
				while(l<=r&&calc(i,u,q[r])<=calc(i,u,k))r--;
				q[++r]=k;
			}
			for(int p=maxp;p>=0;p--){
				while(l<=r&&q[l]>p-1)l++;
				if(l<=r)
					f[u+p*v[i]]=max(f[u+p*v[i]],calc(i,u,q[l])+p*w[i]);
				if(p-c[i]-1>=0){
					while(l<=r&&calc(i,u,q[r])<=calc(i,u,p-c[i]-1))r--;
					q[++r]=p-c[i]-1;
				}
			}
		}
	}
	for(int i=1;i<=m;i++){
		ans=max(ans,f[i]);
	}
	cout<<ans;
	return 0;
} 
4.分组背包
Code
memset(f,0xcf,sizeof(f));
f[0]=0;
	for(int i=1;i<=n;i++){
		for(int j=m;j>=0;j--)
			for(int k=1;k<=c[i];k++)
				for(int k=1;k<=c[i];k++)
					if(j>=v[i][k])
						f[j]=max(f[j],f[j-v[i][k]]+c[i][k]);

标签:状态,背包,int,max,线性,最优,DP
来源: https://www.cnblogs.com/22222222STL/p/15840730.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有