题意:你有N种硬币,每种价值A[i],每种数量C[i],问。在不超过M的情况下,我们用这些硬币,付款有多少种情况。也就是:1,2,3,4,5,....,M这么多种情况下,你能用你的硬币不找钱,付款多少种情况。
例如:
你有一种硬币,价值2,个数2,那么 你是不能付款 3元的。。你只能付款2,或者4元。。
OK,题意差不多就是这样啦。
那么这里有两种方式!
分析:
那么这里我们可以用多重背包来解决,我们把价值和重量看成一样的w[i] = A[i];用M作为背包。那么dp 过后,我们就可以知道 dp[i] 表示的含义为,不超过i元钱的情况下,用拥有的硬币能构成的最大钱数。那么很明显,如果dp[i] = i,意思就是 用拥有的钱,可以刚好构成 i 元钱,上马:
//281MS 648K
#include <stdio.h>
#include <string.h>
#define MAX 102
int ans;//最后答案
int n,m;
int A[MAX],C[MAX];
int dp[100005];
void ZeroOne(int V,int W)
{
for(int i = m; i >= V; i--)
//dp[i] = dp[i]>dp[i-V]+W ? dp[i]:dp[i-V]+W;
if(dp[i]<dp[i-V]+W)
{
dp[i] = dp[i-V]+W;//这里需修改如此统计
if(dp[i] == i) ans ++;//在dp过程中,会有出现dp[j]更新为j的时候 且只有一次,也要放在dp[i]=dp[i-V]+W;此语句后
}
}
int main()
{
while(scanf("%d%d",&n,&m),n+m)
{
ans = 0;
memset(dp,0,sizeof(dp));
for(int i = 1; i <= n; i ++) scanf("%d",&A[i]);
for(int i = 1; i <= n; i ++) scanf("%d",&C[i]);
for(int i = 1; i <= n; i ++)
{
if(A[i]*C[i] >= m)
{
for(int j = A[i]; j <= m; j ++)
//dp[j] = dp[j]>dp[j-A[i]]+A[i] ? dp[j]:dp[j-A[i]]+A[i]; //将价值和重量看做相同
if(dp[j]<dp[j-A[i]]+A[i]) //这里需修改如此统计ans
{
dp[j] = dp[j-A[i]]+A[i];
if(dp[j] == j) ans ++; //在dp过程中,会有出现dp[j]更新为j的时候 且只有一次,也要放在dp[i]=dp[i-V]+W;此语句后
}
}
else
{
int k = 1;
while(k <= C[i])
{
ZeroOne(A[i]*k,A[i]*k);
C[i] -= k;
k *= 2;
}
ZeroOne(C[i]*A[i],C[i]*A[i]);
}
}
//for(int i = 1; i <= m; i ++) if(dp[i]==i)ans++;//这里用以用在hdu,但是poj需要用上面的方式统计ans,不然会超时,过了也过得很险 2654ms........汗。。。。。
printf("%d\n",ans);
}
return 0;
}
那么这里还有一种方式
用flag[i]表示能不能构成 钱为 i 的情况
time[j] 表示,构成 j 元钱的时候,用第 i 种硬币的个数
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 100005
int N,M;
int A[MAX],C[MAX];
bool flag[MAX];
int time[MAX];
int main()
{
while(cin >> N >> M)
{
if(!N && !M)break;
for(int i = 0; i < N; i ++) cin >> A[i];
for(int i = 0; i < N; i ++) cin >> C[i];
int ans = 0;
memset(flag,false,sizeof(flag));
flag[0] = true;
for(int i = 0; i < N; i ++){
memset(time,0,sizeof(time));
for(int j = A[i]; j <= M; j ++){//这里解释为,只有当前j这种情况没有构成,并且j-A[i]的情况存在--(这里也就是类似完全背包,这次状态应该依赖前面存在情况),同时到j为止,用第i种硬币的数量不超过C[i]的情况下才满足条件
if(!flag[j] && flag[j-A[i]] && time[j-A[i]]+1 <= C[i]){
flag[j] = true;
time[j] = time[j-A[i]]+1;
ans ++;
}
}
}
cout << ans <<endl;
}
return 0;
}
个人愚昧观点,欢迎指正与讨论