多重背包可行性贪心+dp解法
就是一个面值已经可以被组成时就尽量少用当前面值的币
#include<iostream> #include<cstdio> #define ri register int #define u int namespace opt { inline u in() { u x(0),f(1); char s(getchar()); while(s<'0'||s>'9') { if(s=='-') f=-1; s=getchar(); } while(s>='0'&&s<='9') { x=(x<<1)+(x<<3)+s-'0'; s=getchar(); } return x*f; } } using opt::in; #define NN 100005 #define MM 100005 #include<cstring> namespace mainstay { u N,M,ans,a[NN],c[NN],f[NN],mi[NN]; inline void solve() { while(1) { N=in(),M=in(),ans=0; if(!N&&!M) return; std::memset(f,0,sizeof(f)),f[0]=1; for(ri i(1); i<=N; ++i) a[i]=in(); for(ri i(1); i<=N; ++i) c[i]=in(); for(ri i(1); i<=N; ++i) { std::memset(mi,0,sizeof(mi)); for(ri j(a[i]); j<=M; ++j) { if(!f[j]&&f[j-a[i]]&&mi[j-a[i]]+1<=c[i]) { mi[j]=mi[j-a[i]]+1,f[j]=1; } } } for(ri i(1); i<=M; ++i) if(f[i]) ++ans; std::cout<<ans<<std::endl; } } } int main() { //freopen("x.txt","r",stdin); std::ios::sync_with_stdio(false); mainstay::solve(); }
多重背包通用优化解法:二进制拆分
#pragma GCC optimize("Ofast") #include<iostream> #include<cstdio> #define ri register int #define u int #define NN 100005 #define MM 100005 #include<cstring> namespace mainstay { u N,M,ans,cnt,b[10000005],a[NN],c[NN],f[NN]; inline void solve() { while(1) { std::cin>>N>>M; ans=cnt=0; if(!N&&!M) return; std::memset(f,0,sizeof(f)),f[0]=1; for(ri i(1); i<=N; ++i) std::cin>>a[i]; for(ri i(1); i<=N; ++i) { std::cin>>c[i]; u _rest(c[i]); for(ri j(1);j<=_rest;j<<=1) b[++cnt]=j*a[i],_rest-=j; b[++cnt]=_rest*a[i]; } for(ri i(1); i<=cnt; ++i) { for(ri j(M);j>=b[i];--j){ f[j]|=f[j-b[i]]; } } for(ri i(1); i<=M; ++i) if(f[i]) ++ans; std::cout<<ans<<std::endl; } } } int main() { //freopen("x.txt","r",stdin); std::ios::sync_with_stdio(false); mainstay::solve(); }