一、01背包问题及其变形
1.未经优化的动归算法:
int volume[1002]; //体积
int value[1002]; //价值
int v; //volume of the bag
int dp[1002][1002];
for(i=volume[0];i<=v;i++)
dp[0][i]=value[0];
for(i=1;i<n;i++){
for(int j=0;j<=v;j++){
if(j<volume[i]||dp[i-1][j]>dp[i-1][j-volume[i]]+value[i])
dp[i][j]=dp[i-1][j];
else dp[i][j]=dp[i-1][j-volume[i]]+value[i];
}
}
cout<<dp[n-1][v]<<endl;
2.优化后的动归算法:
int dp[1002];
for(i=0;i<n;i++){
for(int j=v;j>=volume[i];j--){
if(dp[j-volume[i]]+value[i]>dp[j])
dp[j]=dp[j-volume[i]]+value[i];
}
}
cout<<dp[v]<<endl;
int dp[1000];
struct BG{
int h; //快乐度
int l; //持续时间
int t; //发起人离校时间
};
bool cmp(BG b1,BG b2){
return b1.t<b2.t;
}
BG bg[32];
int main(){
int n,i,j,max;
while(cin>>n&&n>=0){
max=0;
for(i=0;i<n;i++)
cin>>bg[i].h>>bg[i].l>>bg[i].t;
sort(bg,bg+n,cmp); //要先按照发起人离校时间从早到晚排序,因为这里
//的dp数组下标(也就是最晚结束时间)并不是越大对每个bg最有利
max=bg[n-1].t; //所有bg最晚结束时间
for(i=0;i<=max;i++)
dp[i]=0;
for(i=0;i<n;i++)
for(j=bg[i].t;j>=bg[i].l;j--)
if(dp[j-bg[i].l]+bg[i].h>dp[j])
dp[j]=dp[j-bg[i].l]+bg[i].h;
int happy=0;
for(i=0;i<=max;i++) //和01背包另一个不同的地方,因为01背包的dp数组是递增的,而这里的dp[]不是
if(dp[i]>happy)
happy=dp[i];
cout<<happy<<endl;
}
}
二、完全背包问题(需要装满的那类)http://acm.hdu.edu.cn/showproblem.php?pid=1114
for(i=0;i<=v;i++)
dp[i]=INF;
dp[0]=0;
for(i=0;i<n;i++)
for(int j=volume[i];j<=v;j++)
if(dp[j-volume[i]]+value[i]<dp[j])
dp[j]=dp[j-volume[i]]+value[i];
三、区别
前者(01背包)第二层循环必须从后到前(因为每个物品只有一个)
后者(完全背包)第二层循环从前到后可以省去一个循环:for(int k=0;k<v/volume[i];k++)
四、多重背包
http://acm.hdu.edu.cn/showproblem.php?pid=2191
#pragma warning (disable:4786)
#include<iostream>
#include<stdio.h>
#include<vector>
using namespace std;
int n,m;
int dp[102];
int price[102];
int weight[102];
int num[102];
int main(){
int i,j,k,c,n,m;
scanf("%d",&c);
while(c--){
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
scanf("%d%d%d",&price[i],&weight[i],&num[i]);
memset(dp,0,sizeof(dp));
for(i=1;i<=m;i++){
for(j=1;j<=num[i];j++)
for(k=n;k>=price[i];k--){
if(dp[k]<dp[k-price[i]]+weight[i])
dp[k]=dp[k-price[i]]+weight[i];
}
}
printf("%d\n",dp[n]);
}
}