题解 P2347 【砝码称重】

ShineEternal

2019-08-27 10:52:55

Solution

## 题目链接: https://www.luogu.org/problem/P2347 ## 分析: 这道题应该不难看出是一道多重背包的题目。 #### 那么我们会有两种思路: - 按照普通的计算方式,记$f[i]$为背包容量为i时能装到的最大质量。这样最后判断能否装满$(f[i]==i)$即为能否称出一种方案 - 记$f[i]$为能否称出i的质量($0/1$),那么最后就判断有多少个1就行。 #### 那么下面就总结两种方法: - 普通的多重背包做法: ```cpp #include<cstdio> #include<iostream> using namespace std; int v[10],w[10],f[10005]; int main() { v[1]=1; v[2]=2; v[3]=3; v[4]=5; v[5]=10; v[6]=20; int n=6,m; for(int i=1;i<=6;i++) { scanf("%d",&w[i]); m+=v[i]*w[i]; } for(int i=1;i<=6;i++) { for(int j=m;j>=1;j--) { for(int k=0;k<=w[i];k++) { if(j-k*v[i]<0)break; f[j]=max(f[j],f[j-k*v[i]]+k*v[i]); } } } int ans=0; for(int i=1;i<=m;i++) { if(f[i]==i) { ans++; } } printf("Total=%d\n",ans); } ``` - 二进制优化的多重背包做法: ```cpp #include<cstdio> #include<iostream> using namespace std; int v[10],w[100],f[10005],a[10]; int main() { v[1]=1; v[2]=2; v[3]=3; v[4]=5; v[5]=10; v[6]=20; int n=6,m; int n1=0; for(int i=1;i<=6;i++) { scanf("%d",&a[i]); m+=a[i]*v[i]; int t=1; while(a[i]>=t) { w[++n1]=v[i]*t; a[i]-=t; t*=2; } if(a[i]) w[++n1]=v[i]*t; } for(int i=1;i<=n1;i++) { for(int j=m;j>=w[i];j--) { f[j]=max(f[j],f[j-w[i]]+w[i]); } } int ans=0; for(int i=1;i<=m;i++) { if(f[i]==i) { ans++; } } printf("Total=%d\n",ans); return 0; } ```