背包问题

强烈安利: 

背包九讲

 

As a 初学者,背包问题我分了一下四种

 

类型1  01背包问题

【温馨提示】

  01 背包问题 重点理念:

  f[i][v] 表示前 i 件物品(部分或全部)恰放入一个容积为 v 的背包可以获得的最大价值

  转移方程为  f[i][v ]= max ( f[i-1][v] , f[i-1][v-w[i]] + c[i] )

 

(1)简单的01背包  

P1048 采药

代码一:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int te[10000],jia[10000],f[10000][10000];
int main()
{
    int t,m;
    cin>>t>>m;
    for(int i=1;i<=m;i++)
      cin>>te[i]>>jia[i];
    for(int i=1;i<=m;i++)
       for(int j=t;j>=0;j--)
       {
           if(te[i]<=j)
              f[i][j]=max(f[i-1][j],f[i-1][j-te[i]]+jia[i]);  //此处max直接调用的位于《iostream》函数
           else
              f[i][j]=f[i-1][j];
       }
    cout<<f[m][t];
    return 0;
    
    
}

 

代码二:强行降一维,但要注意 f[i] 要开的大一些

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int te[10000],jia[10000],f[1000000];
int main()
{
    int t,m;
    cin>>t>>m;
    for(int i=1;i<=m;i++)
      cin>>te[i]>>jia[i];
    for(int i=1;i<=m;i++)
       for(int j=t;j>=te[i];j--)
       {
           if(f[j]<f[j-te[i]]+jia[i])
 f[j]=f[j-te[i]]+jia[i];
 
       }
    cout<<f[t];
    return 0;
}

【相似题目】

1.P1060 开心的金明   

  【注意:w[i]*=v[i]】

2.P2871 [USACO07DEC]手链Charm Bracelet  

 

(2)  类01背包不超体积

P1049 装箱问题

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int w[1000],f[1000000];
int main()
{
    int v,n;
    cin>>v>>n;
    for(int i=1;i<=n;i++)
       cin>>w[i];
    for(int i=1;i<=n;i++)
      for(int j=v;j>=w[i];j--)
      {
          f[j]=max(f[j],f[j-w[i]]+w[i]);
      }
    cout<<v-f[v];
    return 0; 
}

【温馨提示】

这类题目和类型一相似,但是类型一是考虑最优价值,类型二只是考虑体积

【相似题目】

1.P2639 [USACO09OCT]Bessie的体重问题Bessie

2.P2925 [USACO08DEC]干草出售Hay For 

 

 (3)  稍复杂的01背包

P2430  严酷的训练

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int t[5000],f[5000],q[5000],p[5000];
int main()
{
    
    int rqy,lao,m,n,tem,ak;
    cin>>rqy>>lao>>m>>n;
    ak=lao/rqy;
    for(int i=1;i<=n;i++)
    {
        cin>>t[i];
        t[i]*=ak;
    }
    for(int i=1;i<=m;i++)
        cin>>p[i]>>q[i];    
    cin>>tem;
    
    for(int i=1;i<=m;i++)
      for(int j=tem;j>=t[p[i]];j--)
       {
       
           if(f[j]<f[j-t[p[i]]]+q[i])
              f[j]=f[j-t[p[i]]]+q[i];
       }
    cout<<f[tem];
    return 0;
    
    
}

【温馨提示】

 。。。一点也不复杂。。。就是把之前的 i 换成了一个数组

 

 

类型2  完全背包

P1616 疯狂的采药

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int v[10000],c[10000],f[1000000];
int main()
{
    int t,m;
    cin>>t>>m;
    for(int i=1;i<=m;i++)
      cin>>v[i]>>c[i];
      
    for(int i=1;i<=m;i++)
       for(int j=v[i];j<=t;j++)
           if(f[j]<f[j-v[i]]+c[i])
              f[j]=f[j-v[i]]+c[i];
              
    cout<<f[t];
    return 0; 
}

【温馨提示】

    完全背包就是 每种物品都可以用无限次

    01背包是每种物品只有一件

【相似题目】

P2722 总分 Score Inflation

 

 

 

类型3  二维背包

P1507 NASA的食物计划

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int v[5000],m[5000],k[5000],f[5000][5000];
int main()
{
    
    int V,M,n;
    cin>>V>>M>>n;
    for(int i=1;i<=n;i++)
        cin>>v[i]>>m[i]>>k[i];
        
    for(int i=1;i<=n;i++)
      for(int j=V;j>=v[i];j--)
       for(int z=M;z>=m[i];z--)
           {
           f[j][z]=max(f[j][z],f[j-v[i]][z-m[i]]+k[i]);
        
        } 
    cout<<f[V][M];
    return 0;
    
    
}

【温馨提示】

    二维背包限制条件双重

【附加题目】

P1910 L国的战斗之间谍

 

 

类型4  背包方案数

P1164  小A点菜

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
long long a[50000],f[50000];
int main()
{
    
    int n,m;
    cin>>n>>m;
    f[0]=1;
    for(int i=1;i<=n;i++)
        cin>>a[i];
        
    for(int i=1;i<=n;i++)
      for(int j=m;j>=a[i];j--)
         f[j]+=f[j-a[i]];     //此处累加方案数
    cout<<f[m];
    return 0;
    
    
}

 

 小结

1.  01背包   一个物品只能选一次

     for ( int  j=n ; j>=v[i] ; j-- )    dp[ j ]=max( dp[ j ] , dp[ j - v[i] ] + w[i] ) ;

2.  完全背包    一个物品可以选无限次

    for ( int  j=v[i] ; j<=n ; j++)    dp[ j ]=max( dp[ j ] , dp[ j - v[i] ] + w[i] ) ;

3.二维背包

    dp[ j ][ z ]=max( dp[ j ][ z ] , dp[ j - v[i] ][ z - m[i] ] + k[i] ) ;

4.背包方案数

    dp[ j ]+=dp[ j - a [i] ] ;

 

posted @ 2019-03-12 21:32  晔子  阅读(363)  评论(1编辑  收藏  举报