首页 > 代码库 > 0-1背包

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背包