POJ 1742 Coins(多重背包?)

题解

一个自然的思路是对于每一个物品做一次01背包

然后T飞了。

试着用二进制拆分,还是T了。

单调队列,对不起,懒,不想写。

我们这样想。设dp[i]代表i这个面值前几种硬币是否能凑到

然后对于每一个i,我们用used[i]代表要凑到i这个值至少要多少个当前这种硬币

然后used可以o(m)得到(当dp[i]=1时,used[i]=0,否则dp[i]=used[dp[i-a]]+1),对于一个used[i]<=c我们把dp[i]变为1.

完成了转移这样复杂度为O(n*m)

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 const int N=110;
 8 const int M=100100;
 9 int n,m,dp[M],a[N],c[N],ans,used[M];;
10 int main(){
11     while(scanf("%d%d",&n,&m)!=EOF){
12         if(n==0&&m==0)break;
13         memset(dp,0,sizeof(dp));
14         dp[0]=1;
15         for(int i=1;i<=n;i++){scanf("%d",&a[i]);}
16         for(int i=1;i<=n;i++){scanf("%d",&c[i]);}
17         for(int i=1;i<=n;i++){
18             for(int j=0;j<=m;j++)used[j]=0;
19             for(int j=a[i];j<=m;j++){
20                 if(!dp[j]&&dp[j-a[i]]&&used[j-a[i]]<c[i]){
21                     dp[j]=1;used[j]=used[j-a[i]]+1;
22                 }
23             }
24         }
25         ans=0;
26         for(int i=1;i<=m;i++)ans+=dp[i];
27         printf("%d\n",ans);
28     }
29     return 0;
30 }

猜你喜欢

转载自www.cnblogs.com/Xu-daxia/p/9745866.html