HDU 2844 Coins 多重背包
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2844
Coins
Memory Limit: 32768/32768 K (Java/Others)
输入
The input contains several test cases. The first line of each test case contains two integers n(1 ≤ n ≤ 100),m(m ≤ 100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1 ≤ Ai ≤ 100000,1 ≤ Ci ≤ 1000). The last test case is followed by two zeros.
输出
For each test case output the answer on a single line.
样例输入
3 10
1 2 4 2 1 1
2 5
1 4 2 1
0 0
样例输出
8
4
题解
裸的多重背包,这里提供两种思路:
1、开个cntv数组维护一下第i个背包用了几次,限制一些非法的转移,像完全背包那一做一遍就ok。
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<sstream>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
const int maxn=101010;
int cntv[maxn];
bool dp[maxn];
int v[maxn],c[maxn];
int main() {
int n,m;
while(scf("%d%d",&n,&m)==2&&n){
clr(dp,0);
for(int i=1;i<=n;i++) scf("%d",&v[i]);
for(int i=1;i<=n;i++) scf("%d",&c[i]);
clr(dp,0);
dp[0]=1;
for(int i=1;i<=n;i++){
clr(cntv,0);
for(int j=v[i];j<=m;j++){
if(!dp[j]&&dp[j-v[i]]&&cntv[j-v[i]]<c[i]){
dp[j]=1;
cntv[j]=cntv[j-v[i]]+1;
}
}
}
int ans=0;
for(int i=1;i<=m;i++) ans+=dp[i];
prf("%d\n",ans);
}
return 0;
}
//end-----------------------------------------------------------------------
2、用二进制拆分转化成01背包。
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<sstream>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
const int maxn=101010;
int cntv[maxn];
bool dp[maxn];
int v[maxn],c[maxn];
int main() {
int n,m;
while(scf("%d%d",&n,&m)==2&&n){
clr(dp,0);
for(int i=1;i<=n;i++) scf("%d",&v[i]);
for(int i=1;i<=n;i++) scf("%d",&c[i]);
VI arr;
for(int i=1;i<=n;i++){
int j=1;
//二进制拆分
while(c[i]>0){
if(c[i]>=j){
arr.pb(v[i]*j);
c[i]-=j;
}else{
arr.pb(v[i]*c[i]);
c[i]=0;
}
j<<=1;
}
}
clr(dp,0);
dp[0]=1;
for(int i=0;i<arr.sz();i++){
for(int j=m;j>=arr[i];j--){
dp[j]=dp[j]|dp[j-arr[i]];
}
}
int ans=0;
for(int i=1;i<=m;i++) ans+=dp[i];
prf("%d\n",ans);
}
return 0;
}
//end-----------------------------------------------------------------------