1.P1048 [NOIP2005 普及组] 采药
一眼,0-1背包:时间为体积,草药的价值为价值。
(此处蒟蒻选用双层循环试试水)
#include <bits/stdc++.h>
using namespace std;
int tim[110],val[110];
int dp[110][1010];//dp[i][j]b表示前i株草药,背包容量为j的最优值
int main()
{
int t,m;
cin>>t>>m;
for(int i=1;i<=m;i++)
cin>>tim[i]>>val[i];
for(int i=1;i<=m;i++)
for(int j=0;j<=t;j++){
if(j<tim[i])
dp[i][j] = dp[i][j];
else
dp[i][j] = max(dp[i-1][j],dp[i-1][j-tim[i]]+val[i]);
}
cout<<dp[m][t];
return 0;
}
2.P1616 疯狂的采药
这题是完全背包:将0-1背包的一维数组优化正着写就ok。
#include <bits/stdc++.h>
using namespace std;
long long a[10010],b[10010],dp[10000010];//数据更新了,数组使劲开
//a[]时间,b[]价值
int main()
{
int t,m;
cin>>t>>m;
for(long long i=1;i<=m;i++)
cin>>a[i]>>b[i];
for(int i=1;i<=m;i++)//草药个数
for(int j=a[i];j<=t;j++){//采药时间
dp[j] = max(dp[j],dp[j-a[i]]+b[i]);
}
cout<<dp[t];
return 0;
}
3.P1049 [NOIP2001 普及组] 装箱问题
可以将这题转化成一个0-1背包问题:
1.求最小剩余空间,就是求能够放入的最大体积。
2.把每个物体看成价值和体积均为a[i](即物品体积)。
3.状态转移方程:dp[ j ] = max(dp[ j ],dp[ j-a[ i ] ]+a[ i ])(采用一维数组从后往前遍历进行优化)。
#include <bits/stdc++.h>
using namespace std;
int a[35],dp[20010];//a[]大小对标n,dp[]对标v
int main()
{
int v,n;
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];
return 0;
}
3.P1833 樱花
这个题,emm,就是三种背包极致混搭:
(1) p[ i ] == 1:0-1背包;
(2) p[ i ] == 0:完全背包;
(3) p[ i ] == 其他数:多重背包。(这里多重背包的二进制优化没咋的听懂,就全部暴力转化成0-1背包了,竟然没爆bushi)。
#include <bits/stdc++.h>
using namespace std;
char cx;
int hh1,hh2,mm1,mm2,n;
int t[10010],c[10010],p[10010];
int dp[1010];
int main()
{
cin>>hh1>>cx>>mm1>>hh2>>cx>>mm2>>n;
for(int i=1;i<=n;i++)
cin>>t[i]>>c[i]>>p[i];
int T = (hh2*60+mm2)-(hh1*60+mm1);
for(int i=1;i<=n;i++){
if(p[i] == 1)//0-1背包
for(int j=T;j>=t[i];j--){
dp[j] = max(dp[j],dp[j-t[i]]+c[i]);
}
else if(p[i] == 0)//完全背包
for(int j=t[i];j<=T;j++){
dp[j] = max(dp[j],dp[j-t[i]]+c[i]);
}
else{//多重背包
for(int l=1;l<=p[i];l++)
for(int j=T;j>=l*t[i];j--){
dp[j] = max(dp[j],dp[j-t[i]]+c[i]);
}
}
}
cout<<dp[T];
return 0;
}