HDU-2844
二进制优化
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100500
#define ll long long
ll n,m;
ll num[MAXN],v[MAXN],w[MAXN];
ll dp[MAXN];
void ZeroOnePack(ll w,ll v){
for(int i=m;i>=w;i--){
if(dp[i-w])dp[i]=1;
}
}
void CompletePack(ll w,ll v){
for(int i=w;i<=m;i++){
if(dp[i-w])dp[i]=1;
}
}
void MultiplePack(ll w,ll v,int num){
if(m<=w*num){
CompletePack(w,v);//等价完全背包
return ;
}
else {
int t=1;
while(t<=num){
ZeroOnePack(t*w,t*v);//转化为01背包
num-=t;
t*=2;
}
ZeroOnePack(num*w,num*v);
}
}
int main(){
while(cin>>n>>m,n&&m){
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=1;i<=n;i++){
scanf("%lld",&v[i]);
w[i]=v[i];
}
for(int i=1;i<=n;i++){
scanf("%lld",&num[i]);
}
for(int i=1;i<=n;i++){
MultiplePack(w[i],v[i],num[i]);
}
ll ans=0;
for(int i=1;i<=m;i++){
if(dp[i]!=0)
ans++;
}
cout<<ans<<endl;;
}
return 0;
}
多重背包可行性
dp[i][j]表示使用前i种货币,能够构成j的面值所花费的i货币数量。因为本道题可以借用已使用的第i种货币的数量同时表示是否能构成j面值(dp[i][j]>0表示能构成)。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100500
int n,m;
int num[MAXN],v[MAXN],w[MAXN];
int dp[MAXN],book[MAXN];
int main(){
while(cin>>n>>m,n&&m){
memset(dp,0,sizeof(dp));
memset(book,0,sizeof(book));
dp[0]=1;
for(int i=1;i<=n;i++){
scanf("%d",&v[i]);
w[i]=v[i];
}
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
}
int ans=0;
book[0]=1;
for(int i=1;i<=n;i++){
memset(dp,0,sizeof(dp));
for(int j=v[i];j<=m;j++){
if(!book[j]&&book[j-v[i]]&&dp[j-v[i]]<num[i]){
book[j]=1;
dp[j]=dp[j-v[i]]+1;
ans++;
}
}
}
cout<<ans<<endl;
}
return 0;
}