链接:点击打开链接
题意:给出n种钱的数量和面额,问用这些钱能拼成1~m中的值的数量
代码1:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int dp[100005],w[105],v[105];
int n,m;
int main(){
int i,j,ans;
while(scanf("%d%d",&n,&m)!=EOF&&(m||n)){
for(i=0;i<n;i++)
scanf("%d",&w[i]);
for(i=0;i<n;i++)
scanf("%d",&v[i]);
memset(dp,-1,sizeof(dp));
dp[0]=0; //多重背包
for(i=0;i<n;i++) //先定义dp[i+1][j]为用前i种数加和得到j时第i种数最多剩余多少个
for(j=0;j<=m;j++){ //因此可以推出递推式dp[i+1][j]=v[i](dp[i][j]>=0),dp[i+1][j]=-1
if(dp[j]>=0) //(j<w[i]||dp[i+1][j-w[i]]<=0),否则dp[i+1][j]=dp[i+1][j-w[i]]-1
dp[j]=v[i]; //最后看dp[n][m]是否大于等于0
else if(w[i]>j||dp[j-w[i]]<=0)
dp[j]=-1;
else
dp[j]=dp[j-w[i]]-1;
}
ans=0;
for(i=1;i<=m;i++)
if(dp[i]>=0)
ans++;
printf("%d\n",ans);
}
return 0;
}
代码2:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int w[105],v[105],f[100005],used[100005];
int n,m;
int main(){
int i,j,ans;
while(scanf("%d%d",&n,&m)!=EOF&&(m||n)){
ans=0;
memset(f,0,sizeof(f));
f[0]=1;
for(i=0;i<n;i++)
scanf("%d",&w[i]);
for(i=0;i<n;i++)
scanf("%d",&v[i]);
for(i=0;i<n;i++){ //这是网上很多题解用的方法,通过一个f数组记录已经
memset(used,0,sizeof(used)); //达到的点,used[j]代表用w[i]填满j最少用几个,因此
for(j=w[i];j<=m;j++){ //每循环一次,used数组清零一次
if(!f[j]&&f[j-w[i]]&&used[j-w[i]]<v[i]){
f[j]=1;
used[j]=used[j-w[i]]+1;
ans++;
}
}
}
printf("%d\n",ans);
}
return 0;
}