0-1背包
Posted ALLap
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了0-1背包相关的知识,希望对你有一定的参考价值。
0-1背包:
0-1背包是背包问题的基础,它衍生出来的背包问题大致具有相同的思路。
而既然是属于动态规划的问题,其通法就在于两步:
1)定义状态:ans[i][T]代表着在容量为T时,只从前i个物品选择的最大价值
2)确定状态转移方程:ans[i][T]=max{ans[i-1][T],ans[i][T-t[i]]+v[i]}(第i件物品拿与不拿两种情况的比较)
压缩空间的方法:
用一个一位数组来记录最大价值,在进行选择时选择倒序,这样恰好可以覆盖,具体理解起来可以将每一次的选择过程进行输出,跟着结果分析会好一点。
1 #include<iostream> 2 using namespace std; 3 const int N=302;//数量 4 5 int t[N];//代价 6 int v[N];//价值 7 8 int main() 9 { 10 int T,num;//总容量和物品数量 11 while(cin>>T>>num) 12 { 13 int i,j; 14 for(i=1;i<=num;i++) 15 cin>>v[i]>>t[i]; 16 int *ans=new int[T+1](); 17 for(i=1;i<=num;i++) 18 { 19 int m; 20 for(m=T;m>=t[i];m--)//关键!!反过来写! 21 { 22 if(ans[m]<(ans[m-t[i]]+v[i])) 23 ans[m]=ans[m-t[i]]+v[i]; 24 } 25 } 26 cout<<ans[T]<<"\n"; 27 delete []ans; 28 } 29 return 0; 30 }
变形1:输出选取的每一件物品
做法:在判断的时候用一个数组做上标记,说明在此容量第i件物品要取。最后输出时再根据标记将物品的序号输出(这样输出的是倒序)
1 #include<iostream> 2 #include<string.h> 3 using namespace std; 4 const int N=302;//数量 5 const int Whole=20000; 6 int t[N];//代价 7 int v[N];//价值 8 bool check[N][Whole];//标记物品的取否 9 int main() 10 { 11 int T,num;//总容量和物品数量 12 while(cin>>T>>num) 13 { 14 int i; 15 for(i=1;i<=num;i++) 16 cin>>v[i]>>t[i]; 17 memset(check,false,sizeof(check)); 18 int *ans=new int[T+1](); 19 for(i=1;i<=num;i++) 20 { 21 int m; 22 for(m=T;m>=t[i];m--)//关键!!反过来写! 23 { 24 if(ans[m]<(ans[m-t[i]]+v[i])) 25 { 26 ans[m]=ans[m-t[i]]+v[i]; 27 check[i][m]=true;//在容量为m下,第i个物品要取 28 //cout<<ans[m]<<" "<<check[i][m]<<endl; 29 } 30 } 31 } 32 cout<<ans[T]<<"\n"; 33 34 while(num>0) 35 { 36 if(check[num][T])//在容量为m下,第i个物品要取 37 { 38 cout<<num<<" "; 39 T-=t[num];//取出后,容量减少相应的代价 40 } 41 num--; 42 } 43 cout<<"\n"; 44 45 delete []ans; 46 } 47 return 0; 48 }
变形2:容量恰好完全用完
关键:ans[ ]初始化将ans[0]设为0,其它均为一个很小的负值。
1 #include<iostream> 2 using namespace std; 3 const int N=302;//数量 4 5 int t[N];//代价 6 int v[N];//价值 7 8 int main() 9 { 10 int T,num;//总容量和物品数量 11 while(cin>>T>>num) 12 { 13 int i; 14 for(i=1;i<=num;i++) 15 cin>>v[i]>>t[i]; 16 int *ans=new int[T+1](); 17 for(i=1;i<=T;i++)//关键点,ans[0]为0,其他均为很小的负值 18 { 19 ans[i]=-99999; 20 } 21 for(i=1;i<=num;i++) 22 { 23 int m; 24 for(m=T;m>=t[i];m--) 25 { 26 if(ans[m]<(ans[m-t[i]]+v[i]))//只有ans[0]才有意义,代表着容量恰好用完。其它情况都为一个很小的值。 27 ans[m]=ans[m-t[i]]+v[i]; 28 } 29 } 30 cout<<ans[T]<<"\n"; 31 delete []ans; 32 } 33 return 0; 34 }
以上是关于0-1背包的主要内容,如果未能解决你的问题,请参考以下文章