感想
这周感触很多,从刚开始死活理解不了01背包,连课程视频都看不下去,到到处找资源理解01背包,最终算是对01背包有了初步的认识,后面的完全背包、多重背包、分组背包,在稍微看懂了01背包之后,也起码能看懂在说什么,为什么这么做了。这周起初天天怀疑人生,到后面才算是又慢慢找回自信。这里特别感谢代码随想录,看完他的视频才大概了解了01背包。
下面贴上这周学习的资源:
【精选】动态规划之背包问题(01背包问题、完全背包问题、多重背包问题 I、多重背包问题 II 、分组背包问题)_01背包问题的时间复杂度_小羊努力变强的博客-CSDN博客【精选】多重背包问题---超详细讲解+优化(不懂你揍我)-CSDN博客混合背包二进制优化(伪万能背包模板)_混合背包模板+二进制优化算法描述-CSDN博客信息学奥赛一本通 1270:【例9.14】混合背包-CSDN博客带你学透0-1背包问题!| 关于背包问题,你不清楚的地方,这里都讲了!| 动态规划经典问题 | 数据结构与算法_哔哩哔哩_bilibili
P1833 樱花 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
P1048 采药
#include<iostream>
using namespace std;
int main(){
int t,m; cin>>t>>m;
int time[1010],value[1010],dp[1010];
for(int i=1;i<=m;i++) cin>>time[i]>>value[i];
for(int i=1;i<=m;i++){
for(int j=t;j>=time[i];j--){
dp[j]=max(dp[j],dp[j-time[i]]+value[i]);
}
}
cout<<dp[t];
return 0;
}
直接上代码了,01背包用一维数组时要倒序处理,以防重复取出体积比较小的物品。
P1616 疯狂的采药
#include<iostream>
using namespace std;
int main(){
int t,m; cin>>t>>m;
long long time[10010],value[10010],dp[10000010];
for(int i=1;i<=m;i++) cin>>time[i]>>value[i];
for(int i=1;i<=m;i++){
for(int j=time[i];j<=t;j++){
dp[j]=max(dp[j],dp[j-time[i]]+value[i]);
}
}
cout<<dp[t];
return 0;
}
代码如上,完全背包处理时要正序,因为要保证每一种物品都能尽可能多取。
P1049 装箱问题
#include<iostream>
using namespace std;
int main(){
int v,n; cin>>v>>n;
long long a[100010],dp[100010]={0};
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++){
for(int j=v;j>=a[i];j--)
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
}
cout<<v-dp[v];
return 0;
}
代码如上,这个题相当于value=weight的01背包问题,所以value和weight可用一个数组来表示
P1833 樱花
#include<iostream>
using namespace std;
int gettime(int a,int b,int c,int d){
int res=c*60+d-(a*60+b);
return res;
}
int main(){
int a,b,c,d; char ch1,ch2;
cin>>a>>ch1>>b>>c>>ch2>>d;
int n; cin>>n;
long long time[10010],beautiful[10010],times[10010],dp[10020];
int ddl=gettime(a,b,c,d);
for(int i=1;i<=n;i++) cin>>time[i]>>beautiful[i]>>times[i];
for(int i=1;i<=n;i++){//混合背包
if(times[i]==0){//完全背包
for(int j=time[i];j<=ddl;j++)
dp[j]=max(dp[j],dp[j-time[i]]+beautiful[i]);
}
else if(times[i]==1){//01背包
for(int j=ddl;j>=time[i];j--)
dp[j]=max(dp[j],dp[j-time[i]]+beautiful[i]);
}
else{//多重背包
for(int j=ddl; j >= time[i]; j--)
for(int k = 0; k*time[i] <= j && k <= times[i]; k++)
dp[j] = max(dp[j],dp[j-k*time[i]]+k*beautiful[i]);
}
}
cout<<dp[ddl];
return 0;
}
这个题受益匪浅。首先是这个题把01,完全和多重背包都融合到了一起,其次是这个题存在一种二进制优化的处理方式,但是这个我目前跟着敲的结果还不太对,这里先不写。上面的代码思路非常清晰的写出了几种背包的处理方式,那就再说一下几种的异同,一维01和多重是逆序,完全是正序。然后多重背包要多一层for循环用来遍历k,来填满背包。
下面再谈谈二进制优化,有了这个优化,完全和多重背包都可以被转化成01背包,这样就很方便。写一下我到处看,然后按自己理解敲出来的二进制优化代码,但是它结果不对,我到现在还没看出问题在哪。
#include<iostream>
using namespace std;
int gettime(int a,int b,int c,int d){
int res=c*60+d-(a*60+b);
return res;
}
int cnt=0;
int main(){
int aa,bb,cc,dd; char ch1,ch2;
cin>>aa>>ch1>>bb>>cc>>ch2>>dd;
int t=gettime(aa,bb,cc,dd);
int n; cin>>n;
int time[10010],value[10010],dp[10010];
for(int i=1;i<=n;i++){
int t,v,s; cin>>t>>v>>s;
int k=1;
while(k<=s){
time[cnt]=t*k; value[cnt]=v*k;
s=s-k; k*=2; cnt++;
}
if(s){
cnt++;
time[cnt]=t*s; value[cnt]=v*s;
}
}
for(int i=1;i<=cnt;i++){
for(int j=t;j>=time[i];j--){
dp[j]=max(dp[j],dp[j-time[i]]+value[i]);
}
}
cout<<dp[t];
return 0;
}