第三周普及一班A总结:
第九课(动态规划之01背包):
01背包简介:
01背包是背包问题中最基础的问题。01背包的规定条件是给定几种物品,
每种物品有且只有一个(只能用一次),并且有价值和体积两个方面。在
01背包问题中,因为每种物品只有一个,对于每个物品只需要考虑选与不选
两种情况。如果不选择将其放入背包中,则不需要处理;如果选择将其放入
背包中,由于不知道之前放入的物品占了多大的空间,需要枚举将这个物品
放入背包后可能占背包空间的所有可能。
01背包基础代码与优化:
二维写法(优化前):
cin>>t>>m;
for(int i=1;i<=m;i++){
cin>>w[i]>>c[i];
}
for(int i=1;i<=m;i++)
for(int j=1;j<=t;j++){
if(j>=w[i])dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+c[i]);
else dp[i][j]=dp[i-1][j];
}
cout<<dp[m][t];
一维写法(优化后):
cin>>t>>m;
for(int i=1;i<=t;i++){
cin>>w[i]>>c[i];
}
for(int i=1;i<=t;i++)
for(int j=m;j>=w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
cout<<dp[m];
一维写法可以防止空间超限(MLE)。
第十课(动态规划之其他背包):
完全背包简介:
完全背包的特点是每种物品数量没有限制,可以无限使用。全背包问题与
01背包的解法相似,状态定义也完全一致。其不同点只是次数限制方面。
基础代码:
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>w[i]>>c[i];
}
for(int i=1;i<=m;i++)
for(int j=w[i];j<=n;j++){
dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
}
cout<<dp[n];
注意:01背包的循环变量j为递减计算,而完全背包是递增计算。
多重背包简介:
与01背包相似,有规定次数限制,每样物品可以取x次。包括01背包也能够
想成次数为1的多重背包来计算。
基础代码:
for(int j=v;j>=w[i];j--)
for(int k=1;k<=p[i] and k*w[i]<=j;k++){
dp[j]=max(dp[j],dp[j-k*w[i]]+k*c[i]);
sum=max(sum,dp[j]);
}
cout<<sum;
混合背包简介:
将01背包,完全背包,多重背包组合成的多样性背包问题。因为01背包可以看作
特殊的多重背包,所以可以忽略不写。
基础代码:
cin>>v>>n;
for(int i=1;i<=n;i++)cin>>w[i]>>c[i]>>p[i];
for(int i=1;i<=n;i++){
if(p[i]==0)
for(int j=w[i];j<=v;j++){
dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
sum=max(sum,dp[j]);
}
else
for(int j=v;j>=w[i];j--)
for(int k=1;k<=p[i] and k*w[i]<=j;k++){
dp[j]=max(dp[j],dp[j-k*w[i]]+k*c[i]);
sum=max(sum,dp[j]);
}
}
cout<<sum;
分组背包简介:
分组背包是01背包的一种变形。分组背包中物品被分成几组,每组中只能挑选出
一件物品加入背包,这是与01背包的区别。
基础代码:
cin>>m>>n>>t;
for (int i=1;i<=n;i++){
cin>>a>>b>>c;
v[c].push_back(b);
w[c].push_back(a);
}
for (int i=1;i<=t;i++){
for (int j=m;j>=0;j--){
for (int k=0;k<w[i].size();k++){
if(j>=w[i][k]){
dp[j]=max(dp[j],dp[j-w[i][k]]+v[i][k]);
}
}
}
}
cout<<dp[m];
第十一课(线性动态规划):
最长上升子序列(LIS):
对于一个数的序列bi,当b1<b2<...<bS的时候,我们称这个序列是上升的。
对于给定的一个序列(a1,a2,...,an),我们可以找到一些上升的子序列(ai1
,ai2,...,aiK),这里1 <= i1 < i2 < ... < iK <= N。比如,对于序列(
1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等
等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8)。
基础代码:
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
dp[i]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if(a[j]<a[i]){
dp[i]=max(dp[i],1+dp[j]);
}
}
sum=max(sum,dp[i]);
}
cout<<sum;
最长公共子序列(LCS):
最长公共子序列(LCS)是一个在一个序列集合中用来查找所有序列中最长子序列的问题。
基础代码:
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
dp[i]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if(a[j]<a[i]){
dp[i]=max(dp[i],1+dp[j]);
}
}
sum=max(sum,dp[i]);
}
cout<<sum;
3 个赞