背包(纯模板)

回忆一下动规中的背包。。。

一. 最基本的 01背包:

描述:

  一个旅行者有一个最多能装 m 公斤的背包,现有 n 件物品 ,它们的重量分别为 W1、W2……Wn ,它们的价值分别为 C1、C2……Cn ,求旅行者能获得的最大总价值。

输入:

  第一行:两个整数,m(背包容量)和 n(物品数量);

  第二行至 n+1 行:每行两个整数 Wi、Ci,表示每个物品的重量和价值。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#include<deque>
#include<stack>
#include<map>
#include<set>
using namespace std;
#define maxm 2001
#define maxn 301
int m,n;
int w[maxn],c[maxn];
int f[maxn][maxm];
inline int read()
{
    int kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(ls=='-')
        kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return kr*xs;
}
int main()
{
    m=read();n=read();
    for(int i=1;i<=n;i++)
        w[i]=read(),c[i]=read();
    for(int i=1;i<=n;i++)
        for(int v=m;v>0;v--)//逆序
            if(w[i]<=v)
                f[i][v]=max(f[i-1][v],f[i-1][v-w[i]]+c[i]);
            else f[i][v]=f[i-1][v];
    printf("%d\n",f[n][m]);
return 0;
}

二. 完全背包

描述:

  设有 n 种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重为 m ,今从 n 种物品中选取若干件(同一种物品可以多次选取)使其重量的和 ≤ m ,而价值的和为最大。

输入:

  第一行:两个整数,m(背包容量)和 n (物品数量);

  第二行至 n+1 行:每行两个整数 Wi、Ci,表示每个物品的重量和价值。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#include<deque>
#include<stack>
#include<map>
#include<set>
using namespace std;
#define maxm 2001
#define maxn 301
int m,n;
int w[maxn],c[maxn];
int f[maxn][maxm];
inline int read()
{
    int kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(ls=='-')
        kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return kr*xs;
}
int main()
{
    m=read();n=read();
    for(int i=1;i<=n;i++)
        w[i]=read(),c[i]=read();
    for(int i=1;i<=n;i++)
        for(int v=1;v<=m;v++)//正序(与01背包的唯一不同) 
            if(w[i]<=v)
                f[i][v]=max(f[i-1][v],f[i-1][v-w[i]]+c[i]);
            else f[i][v]=f[i-1][v];
    printf("%d\n",f[n][m]);
return 0;
}

三. 多重背包

描述:

  有 n 种物品和一个容量为 m 的背包。每种物品都有各自的价值 Wi 、重量 Vi 、和能够购买数量 Si

输入:

  第一行:两个整数,n (物品种数)和 m(背包容量);

  第二行至 n+1 行:每行三个整数 Vi、Wi、Si 表示每种物品的重量、价值和能够购买的最大数量。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#include<deque>
#include<stack>
#include<map>
#include<set>
using namespace std;
#define maxn 6002
int v[maxn],w[maxn],s[maxn];
int f[maxn];
int n,m;
inline int read()
{
    int kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(ls=='-')
        kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return kr*xs;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
        v[i]=read(),w[i]=read(),s[i]=read();
    for(int i=1;i<=n;i++)
        for(int j=m;j>=0;j--)//以上两重循环为 01背包 
            for(int k=0;k<=s[i];k++)
            {
                if(j-k*v[i]<0) break;//放不下(判) 
                f[j]=max(f[j],f[j-k*v[i]]+k*w[i]);
            }
    printf("%d\n",f[m]);
return 0;
}

四. 混合背包(01+完全+多重)

描述:

  一个旅行者有一个最多能装 m 公斤的背包,现有 n 件物品,它们的重量分别为 W1、W2……Wn ,它们的价值分别为 C1、C2……Cn 。有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。求解将那些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

输入:

  第一行:两个整数, m (背包容量)和 n (物品数量);

  第二行至 n+1 行:每行三个整数 Wi、Ci、Pi ,前两个整数分别表示每个物品的重量、价值,第三个整数若为 0 ,则说明此物品可以购买无数件;若为其它数字,则为此物品可够买的最多件数(Pi)。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#include<deque>
#include<stack>
#include<map>
#include<set>
using namespace std;
#define maxn 6002
int w[maxn],c[maxn],p[maxn];
int f[maxn];
int n,m;
inline int read()
{
    int kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(ls=='-')
        kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return kr*xs;
}
int main()
{
    m=read();n=read();
    for(int i=1;i<=n;i++)
        w[i]=read(),c[i]=read(),p[i]=read();
    for(int i=1;i<=n;i++)
        if(p[i]==0)//完全背包 
        {
            for(int j=w[i];j<=m;j++)
                f[j]=max(f[j],f[j-w[i]]+c[i]);
        }
        else//01背包和多重背包 
        {
            for(int j=1;j<=p[i];j++)
                for(int k=m;k>=w[i];k--)
                f[k]=max(f[k],f[k-w[i]]+c[i]);
        }
    printf("%d\n",f[m]);
return 0;
}

五. 二维费用背包

描述:

  有一个背包,容纳的重量为 m 、体积为 v 。有 n 件物品,其质量为 Wi、体积为 Vi、价值为 Ci 。求,在不超过背包容纳的最大重量和体积的情况下,所能够获得的最大价值。

输入:

  第一行:三个整数, v(背包容纳的体积)、m(背包容纳的质量)、n(物品数量);

  第二行至 n+1 行:每行三个整数 Vi 、Wi、C,分别表示物品的体积、重量和价值。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#include<deque>
#include<stack>
#include<map>
#include<set>
using namespace std;
#define maxn 1001 
int m[maxn],v[maxn],c[maxn];
int f[maxn][maxn];
int N,V,M;
inline int read()
{
    int kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(ls=='-')
        kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return kr*xs;
}
int main()
{
    V=read();M=read();N=read(); 
    for(int i=1;i<=N;i++)
        v[i]=read(),m[i]=read(),c[i]=read();
    for(int i=1;i<=N;i++)
        for(int j=V;j>=v[i];j--)
            for(int k=M;k>=m[i];k--)//比01背包多一维条件 
                f[j][k]=max(f[j][k],f[j-v[i]][k-m[i]]+c[i]);
    printf("%d\n",f[V][M]);
    return 0;
}

六. 分组背包

描述:

  一个旅行者有一个最多能装 m 公斤的背包,现在有 n 件物品,它们的重量分别为 W1、W2……Wn ,它们的价值分别为 C1、C2……Cn 。这些物品被分为若干组,每组中的物品互相冲突,最多选一件。求解将那些物品装入背包可使这些物品的费用总和不超过背包容量,且价值最大。

输入:

  第一行:三个整数,m (背包容量)、n (物品数量)和 T (最大组号);

  第二行至 n+1 行:每行三个整数 W、C、P,表示每个物品的重量、数量和所属组号。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#include<deque>
#include<stack>
#include<map>
#include<set>
using namespace std;
#define maxn 1001
int n,m,t;
int w[maxn],c[maxn];
int a[maxn][maxn];
int f[maxn]; 
inline int read()
{
    int kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(ls=='-')
        kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return kr*xs;
}
int main()
{
    m=read();n=read();t=read();
    for(int i=1;i<=n;i++)
    {
        int p;
        w[i]=read();c[i]=read();p=read();
        a[p][++a[p][0]]=i;//(++a[p][0]为每组的数量) 
    }
    for(int k=1;k<=t;k++)
        for(int j=m;j>=0;j--)
            for(int i=1;i<=a[k][0];i++)
                if(j>=w[a[k][i]])
                {
                    int tmp=a[k][i];//记录该物品所属的组号 
                    f[j]=max(f[j],f[j-w[tmp]]+c[tmp]);
                }
    printf("%d\n",f[m]);
return 0;
}

 

posted @ 2018-09-25 20:12  落笔映惆怅丶  阅读(255)  评论(0编辑  收藏  举报