背包简记

背包问题的思想很不错,个人学习后收获很多。它是将一个问题分解成若干个子问题,并以解决子问题达到解决原问题的一种解题思想。接下来我准备复习一下3个简单的背包问题,以便日后回忆起来能很快。

1:数塔问题

题目:HDU 2084.

解题思想:每下一层的最大值都能通过上一层的遍历得到,只要不断记录下一层就能得到的最低层的最大结果。(应该是背包问题中最简单的了吧);

代码如下:

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int max(int a,int b)
 5 {
 6 return a>b?a:b;
 7 }
 8 
 9 int main()
10 {
11 int n;//多组输入; 
12 while(cin>>n)
13 {
14 while(n--)
15 {
16 int m,a[105][105]={0},dp[105][105],ans=-1;
17 cin>>m;//数塔层数; 
18 for(int i=1;i<=m;i++)
19 for(int j=1;j<=i;j++)
20 cin>>a[i][j];
21 memset(dp,0,sizeof(dp));
22 for(int i=1;i<=m;i++)
23 for(int j=1;j<=i;j++)
24 dp[i][j]=a[i][j]+max(dp[i-1][j-1],dp[i-1][j]);//记录每一层的最大值; 
25 for(int j=1;j<=m;j++)
26 ans=max(ans,dp[m][j]);//比较最低一层的最大数据; 
27 cout<<ans<<endl;
28 }
29 }
30 return 0;
31 }

2:最长增序列

题目:百练 2757.

解题思想:记录每个数之前的最大增序列,最后遍历一遍记录数据,得到最大增序列长度;(难度略稍于数塔之后,属于简单的背包问题);

代码如下:

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int max(int a,int b)
 5 {
 6 return a>b?a:b;
 7 }
 8 
 9 int main()
10 {
11 int n;//数组长度; 
12 while(cin>>n)
13 {
14 int dp[35],a[35],ans=0; 
15 for(int i=1;i<=n;i++)
16 cin>>a[i];
17 memset(dp,0,sizeof(dp));
18 for(int i=1;i<=n;i++)//遍历到第i个数; 
19 for(int j=1;j<=i;j++)//遍历第一个数到到这第i个数; 
20 if(a[i]>a[j]) 
21 dp[i]=max(dp[j]+1,dp[i]);// 不断更新第i个数之前的最长增序列有多少个 ;
22 for(int i=1;i<=n;i++) 
23 ans=max(dp[i],ans);//最后遍历一遍记录数据; 
24 cout<<ans+1<<endl;
25 }
26 return 0;
27 }

/*

举个例子好理解:

8

3 7 1 8 2 5 6 9

第一个数是3;3之前没有比3小的数,所以dp[1]=0;第二个数是7;之前有比它小的3,所以dp[2]=1;接着dp[3]=0;到dp[4]时,遍历dp[1]时,因为满足8>3,暂时dp[4]更新为1;遍历到dp[2]时,因为8>7,此时dp[2](为2)>当时dp[4](为1)所以,dp[4]更新为2;再遍历dp[3]时,虽然8>1,但此时dp[4]>dp[3],所以dp[4]保留原值2......一直到9时,dp[8]更新为4;最后遍历一遍dp[1]-dp[8]:0,1,0,2,1,2,3,4得到dp[8]最大,所以最长增序列为dp[8]+1=5(加9本身);

*/

3.01背包问题

题目:HDU 2546(一类题)

解题思想:01背包就是拿与不拿的问题;当给定一个背包容器,各物体重量和价值时,我们就一个一个来试试,并把我们试的数据储存下来(试的时候用到了辅助背包,就是重量为1到背包最大重量的背包,怎么用等下讲),方便下一次试的时候在已有的数据里拿出最大的那组数据;(就是解决子问题嘛,为方便回忆,等下列出01背包表并详细解释表格的数据代表什么,便于灵活运用)

代码如下:

 1 #include<iostream> 
 2 #include<cstring>
 3 using namespace std;
 4 int max(int a,int b)
 5 {
 6     return a>b?a:b;
 7 }
 8 
 9 int main()
10 {
11     int num,maxspace;//num代表背包个数,maxspace代表背包最大容量 
12     while(cin>>num>>maxspace)
13     {
14         int weight[10],value[10],dp[11][100];//weight为每个背包重量,value为每个背包价值 
15         for(int i=1;i<=num;i++)
16         cin>>weight[i];
17         for(int i=1;i<=num;i++)
18         cin>>value[i];
19         memset(dp,0,sizeof(dp));
20         for(int i=1;i<=num;i++)//尝试第i个背包 
21         for(int j=1;j<=maxspace;j++)//重量为1到maxspace重的背包来尝试第i个背包 
22         if(j>=weight[i])//如果承重为j的背包可以放 
23         dp[i][j]=max(value[i]+dp[i-1][j-weight[i]],dp[i-1][j]);//放入i的价值加上之前以记录承重为j-weight[i] 的最大价值和没加的i-1物体承重为j的最大价值;(绕口) 
24         else
25         dp[i][j]=dp[i-1][j];//如果放不下则直接保存i-1物体承重为j的最大价值;(好像不用else也行,因为放不进去的数据不会用到) 
26         cout<<dp[num][maxspace]<<endl;//dp[num][maxspace]肯定为最大值,等下看表一目了然; 
27         //以下为打表
28         for(int i=1;i<=num;i++)
29         {
30             for(int j=1;j<=maxspace;j++)
31                 cout<<dp[i][j]<<"	";
32             cout<<endl; 
33         }
34     }
35     return 0;
36 }

/*

依然举例说明:

先说dp[i][j]代表面对前i件物品,辅助背包容量为j时,所取得的最大价值。

5个物品,背包承重为10;5行从上往下为面对第i个物体,10列为重量1-10的辅助背包;

先看第一行第一列dp[1][1];因为中量为1的辅助背包不能放下质量为2的第一个物品,所以最大价值为0,之后辅助背包大于等于二后能放,于是dp[1][1]-dp[1][10]都为4;再面对第2个物品,主要看dp[2][3]和dp[2][4];dp[2][3]表示只放了2,而dp[2][4]则为放了4;又在dp[2][6]时的10是因为辅助背包为6时,6>4;可以放入,但值得注意的是,试空间为6的背包时就用到了dp[2-1][6-4]即dp[1][2]时的数据,此时表示刚好放入我就放,我们知道,在此之前的数据都是最大的,此时得出的数据就也是最大的,之后依此类推;再看dp[3][3]辅助背包承重为3时,可以放物体1或3;但物体3的价值大于物体一的价值,于是最大数据就被更新了,总之在得出最大数据时,我们在不断更新最大数据,得出的答案便在最后一个(最后一个数据时从之前的数据得来的)。

差不多就这样吧,表达能力有限,自己懂就行,其他人,随缘吧。

*/

原文地址:https://www.cnblogs.com/wwq-19990526/p/8606708.html