我们先来看分组背包问题
有N件物品和一个容量为V的背包,第i件物品的重量为c[i],价值为w[i],这些物品被划分成了若干组,每组中的物品互相冲突,最多选一件
问将哪些物品放入背包中可以使背包获得最大的价值
我们用f[k][v]表示前k种物品花费费用v所能取得的最大价值
给出状态转移方程:
f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于第k组}
可以看出,这个问题还是很显然的,下面给出完整的实现:
在实现的时候稍微皮了一下~~
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 const int maxn=105; 6 const int maxv=105; 7 const int maxt=15; 8 int N,V,T; 9 int v[maxn],w[maxn]; 10 int f[maxv]; 11 int a[maxt][maxn]; 12 int main() 13 { 14 cin>>V>>N>>T; 15 for(int i=1;i<=N;i++) 16 { 17 int p; 18 cin>>v[i]>>w[i]>>p; 19 a[p][++a[p][0]]=i; //存每一组的所有物品的编号 20 //a[p][0]表示第p组一共有几个物品 21 } 22 for(int i=1;i<=T;i++) 23 for(int j=V;j>=0;j--) 24 for(int k=1;k<=a[i][0];k++) 25 if(j-v[a[i][k]]>=0) 26 f[j]=max(f[j],f[j-v[a[i][k]]]+w[a[i][k]]); 27 cout<<f[V]<<endl; 28 return 0; 29 } 30
下面介绍有依赖的背包,参考题目为NOIP金明的预算方案
在这种背包中引入了主件和附件的概念,只有放了主件之后才能放与之相关联的附件
最开始我是用生成组合的形式来解决这个问题的
即以主件为基准,和每一种附件的情况进行捆绑,再放01背包
但是我们有更皮的解决方法
将每一个主件对应的附件集合先做一次01背包
下面给出一道例题来实现这个方法,本例题中的主件是没有价值的,如果主件有价值可以在这个的基础上进行简单的修改
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 const int maxn=55; 6 const int maxv=100005; 7 int tmp[maxv]; 8 int f[maxn][maxv]; 9 int N,V; //主件的数量,背包的容量 10 int main() 11 { 12 while(cin>>N>>V) 13 { 14 memset(f,0,sizeof(f)); 15 for(int i=1;i<=N;i++) 16 { 17 memset(tmp,-1,sizeof(tmp)); 18 int p,m; //主件的费用,附件的数量 19 cin>>p>>m; 20 for(int j=p;j<=V;j++) 21 tmp[j]=f[i-1][j-p]; 22 int v,w; 23 for(int j=1;j<=m;j++) 24 { 25 cin>>v>>w; //每一个附件的重量和价值 26 for(int k=V;k>=v;k--) 27 if(tmp[k-v]!=-1) 28 tmp[k]=max(tmp[k],tmp[k-v]+w); 29 } 30 for(int j=V;j>=0;j--) 31 f[i][j]=max(tmp[j],f[i-1][j]); 32 } 33 cout<<f[N][V]<<endl; 34 } 35 return 0; 36 }
另外,如果附件是另一件物品的主件,就是树形动态规划了,参考选课那道题目,将在以后进行介绍