背包(纯模板)
回忆一下动规中的背包。。。
一. 最基本的 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、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 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 行:每行三个整数 Wi 、Ci 、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; }