P1048 [NOIP2005 普及组] 采药
思路:
1.每株药采一次,在一定时间内所采价值最大为 01背包问题
2.以dp[j]表示当在总共时间为j时可采的最大价值
3.每一种药依次遍历,内部时间从大到小遍历(防止一种药重复计算),得出最大值
代码:
#include<bits/stdc++.h>
using namespace std;
int t,m,a[105],b[105],dp[1005];
int main(){
cin>>t>>m;
for(int i=0;i<m;i++){
cin>>a[i]>>b[i];
}
for(int i=0;i<m;i++){
for(int j=t;j>=a[i];j--){
dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
}
}
cout<<dp[t];
}
P1616 疯狂的采药
思路:
1.每株药无限采摘,为完全背包问题
2.大体思路与上题一致,内部时间循环转变为从小到大,使得每种药可重复计算
代码:
#include<bits/stdc++.h>
using namespace std;
long long int t,m,a[10000005],b[10005],dp[10000005];
int main(){
cin>>t>>m;
for(int i=0;i<m;i++){
cin>>a[i]>>b[i];
}
for(int i=0;i<m;i++){
for(long long int j=a[i];j<=t;j++){
dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
}
}
cout<<dp[t];
}
P1049 [NOIP2001 普及组] 装箱问题
思路:
1.题目可以转化为在n个物品中取(每个一次)可填满的最大体积为多少,即01背包问题
2.思路大体与第一题一致,不过限制与需求一致都为体积
3.最后输出再用箱子的体积减去最大体积即剩下的最小体积
代码:
#include<bits/stdc++.h>
using namespace std;
int v,n,a[35],dp[20005];
int main(){
cin>>v>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;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];
}
P1833 樱花
思路:
1.本题将01背包多重背包和完全背包的情况混在了一起
2.可以通过判断可使用个数分类处理
3.完全背包(p=0)直接遍历解;01背包和多重背包可以合在一起解(可用二进制优化)
代码:
#include<bits/stdc++.h>
using namespace std;
int n,h1,h2,m1,m2,T,cnt,k,a,b;
int c[10005],p[10005],t[10005],dp[10005];
int c1[10005],t1[10005];
int main(){
scanf("%d:%d %d:%d",&h1,&m1,&h2,&m2);
cin>>n;
if(m2<m1){
m2=m2+60;
h2--;
}
T=(h2-h1)*60+m2-m1;
for(int i=0;i<n;i++)
scanf("%d%d%d",&t[i],&c[i],&p[i]);
for(int i=0;i<n;i++){
if(p[i]==0){
for(int j=t[i];j<=T;j++){
dp[j]=max(dp[j],dp[j-t[i]]+c[i]);
}
}
else{
cnt=1;
k=1;
a=c[i];
b=t[i];
while(p[i]>=k){
t1[cnt]=b*k;
c1[cnt++]=a*k;
p[i]-=k;
k*=2;
}
t1[cnt]=b*p[i];
c1[cnt++]=a*p[i];
for(int k=1;k<cnt;k++){
for(int j=T;j>=t1[k];j--){
dp[j]=max(dp[j],dp[j-t1[k]]+c1[k]);
}
}//二进制优化
/*for(int k=1;k<=p[i];k++){
for(int j=T;j>=t[i];j--){
dp[j]=max(dp[j],dp[j-t[i]]+c[i]);
}
}直接解多重背包*/
}
}
cout<<dp[T];
}