这两道都是洛咕上多重背包的模板题,然后第二道题前面还要稍微处理一下字符串???
二进制拆分法(第一题的代码)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=100005;
int val[N],w[N],f[N];
int main(){
int n=read(),W=read(),tot=0,ans=0;
for(int i=1;i<=n;++i){
int v=read(),weight=read(),c=read();
for(int j=1;j<=c;j<<=1){
val[++tot]=j*v;
w[tot]=j*weight;
c-=j;
}
if(c)val[++tot]=c*v,w[tot]=c*weight;
}
for(int i=1;i<=tot;++i)
for(int j=W;j>=w[i];--j)
f[j]=max(f[j],f[j-w[i]]+val[i]);
for(int i=1;i<=W;++i)ans=max(ans,f[i]);
printf("%d\n",ans);
return 0;
}
单调队列优化(第一题代码)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=105;
int a[N],b[N],c[N],q[40005],pre[N][40005];
int main(){
int n=read(),m=read();
for(int i=1;i<=n;++i)b[i]=read(),a[i]=read(),c[i]=read();
for(int i=1;i<=n;++i)
for(int j=0;j<a[i];++j){
int l=1,r=0;
for(int k=j;k<=m;k+=a[i]){
while(l<=r&&k-q[l]>c[i]*a[i])++l;
while(l<=r&&pre[i-1][q[r]]-q[r]/a[i]*b[i]<pre[i-1][k]-k/a[i]*b[i])--r;
q[++r]=k;
pre[i][k]=pre[i-1][q[l]]+(k-q[l])/a[i]*b[i];
}
}
int ans=0;
for(int i=1;i<=m;++i)ans=max(ans,pre[n][i]);
printf("%d\n",ans);
return 0;
}
单调队列优化法(第二题的代码)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=10005;
int v[N],w[N],c[N],q[100005],f[100005];
int main(){
string s1,s2;cin>>s1>>s2;
int ans1,ans2;
for(int i=0;i<s1.size();++i){
if(s1[i]==':'){
int cnt1=0,cnt2=0;
for(int j=0;j<=i-1;++j){
cnt1=cnt1*10+s1[j]-'0';
}
for(int j=i+1;j<s1.size();++j){
cnt2=cnt2*10+s1[j]-'0';
}
ans1=cnt1*60+cnt2;
break;
}
}
for(int i=0;i<s2.size();++i){
if(s2[i]==':'){
int cnt1=0,cnt2=0;
for(int j=0;j<=i-1;++j){
cnt1=cnt1*10+s2[j]-'0';
}
for(int j=i+1;j<s2.size();++j){
cnt2=cnt2*10+s2[j]-'0';
}
ans2=cnt1*60+cnt2;
break;
}
}
//以上对字符串的处理,只是为了求出背包体积m
int n=read(),m=ans2-ans1;
for(int i=1;i<=n;++i){
w[i]=read(),v[i]=read(),c[i]=read();
if(c[i]==0)c[i]=1000;
}
for(int i=1;i<=m;++i)f[i]=-1e9;
for(int i=1;i<=n;++i){
for(int j=0;j<w[i];++j){
int l=1,r=0,maxk=(m-j)/w[i];
for(int k=maxk-1;k>=max(maxk-c[i],0);--k){
while(l<=r&&f[j+q[r]*w[i]]-q[r]*v[i]<=f[j+k*w[i]]-k*v[i])--r;
q[++r]=k;
}
for(int k=maxk;k>=0;--k){
while(l<=r&&q[l]>k-1)++l;
if(l<=r)f[j+k*w[i]]=max(f[j+k*w[i]],f[j+q[l]*w[i]]+(k-q[l])*v[i]);
if(k-c[i]-1>=0){
while(l<=r&&f[j+q[r]*w[i]]-q[r]*v[i]<=f[j+(k-c[i]-1)*w[i]]-(k-c[i]-1)*v[i])--r;
q[++r]=k-c[i]-1;
}
}
}
}
int ans=0;
for(int i=1;i<=m;++i)ans=max(ans,f[i]);
printf("%d\n",ans);
return 0;
}
一般来说,二进制拆分法比较容易理解也比较好写,一般的题目用二进制拆分就够了,单调队列的时间复杂度可能更加稳定更加优秀.