题目大意:某人有各种面值为ai的硬币ci个,问他能凑够1到m价格中的几个?
Input
The input contains several test cases. The first line of each test case contains two integers n(1<=n<=100),m(m<=100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1<=Ai<=100000,1<=Ci<=1000). The last test case is followed by two zeros.
Output
For each test case output the answer on a single line.
Sample Input
3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0
Sample Output
8 4
动态规划,
dp[i][j]表示用前 i 个物品凑成 j 时物品还剩多少个,如果凑不出,就为-1
代码如下
1 /* 2 if(dp[i-1][j] >= 0) { 3 dp[i][j] = c[i]; 4 } 5 else { 6 if(j < v[i] || dp[i][j-v[i]] < 0) { 7 dp[i][j] = -1; 8 } 9 else { 10 dp[i][j] = dp[i][j-v[i]] - 1; 11 } 12 }*/ 13 #include <cstdio> 14 #include <cstring> 15 #include <cstdlib> 16 17 int dp[102][100002]; 18 int a[102], c[102]; 19 int main(int argc, char const *argv[]) 20 { 21 int n, m; 22 freopen("input.txt","r",stdin); 23 while(scanf("%d %d",&n,&m) != EOF && (n != 0 && m != 0)) { 24 for(int i = 1; i <= n; i++) { 25 scanf("%d",&a[i]); 26 } 27 for(int i = 1; i <= n; i++) { 28 scanf("%d",&c[i]); 29 } 30 memset(dp, 0, sizeof(dp)); 31 for(int i = 1; i <= n; i++) { 32 dp[i][0] = c[i]; 33 } 34 for(int i = 0; i <= m; i++) { 35 dp[0][i] = -1; 36 } 37 for(int i = 1; i <= n; i++) { 38 for(int j = 1; j <= m; j++) { 39 if(dp[i-1][j] >= 0) { 40 dp[i][j] = c[i]; 41 } 42 else { 43 if(j < a[i] || dp[i][j-a[i]] < 0) { 44 dp[i][j] = -1; 45 } 46 else { 47 dp[i][j] = dp[i][j-a[i]] - 1; 48 } 49 } 50 } 51 } 52 int ans = 0; 53 for(int i = 1; i <= m; i++) { 54 if(dp[n][i] >= 0) { 55 ans++; 56 } 57 } 58 printf("%d ",ans); 59 } 60 return 0; 61 }
关于转移方程,如果dp[i-1][j] >= 0 即用前i-1个物品就可以实现j,那么dp[i][j]就是第i个物品的个数
如果dp[i-1][j] == -1
如果j比第i个物品的价值小,那么凑不出
如果用前i个物品凑不出j-v[i],那么也同样凑不出j
否则,dp[i][j]就为凑过j-1的物品数再减1
再将dp化为一维数组
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 5 int dp[100002]; 6 int a[102], c[102]; 7 int main(int argc, char const *argv[]) 8 { 9 int n, m; 10 //freopen("input.txt","r",stdin); 11 while(scanf("%d %d",&n,&m) != EOF && (n != 0 && m != 0)) { 12 for(int i = 1; i <= n; i++) { 13 scanf("%d",&a[i]); 14 } 15 for(int i = 1; i <= n; i++) { 16 scanf("%d",&c[i]); 17 } 18 memset(dp, 0, sizeof(dp)); 19 for(int i = 1; i <= m; i++) { 20 dp[i] = -1; 21 } 22 for(int i = 1; i <= n; i++) { 23 for(int j = 0; j <= m; j++) { 24 if(dp[j] >= 0) { 25 dp[j] = c[i]; 26 } 27 else if( j < a[i] || dp[j-a[i]] < 0) { 28 dp[j] = -1; 29 } 30 else { 31 dp[j] = dp[j-a[i]] - 1; 32 } 33 } 34 } 35 int ans = 0; 36 for(int i = 1; i <= m; i++) { 37 if(dp[i] >= 0) { 38 ans++; 39 } 40 } 41 printf("%d ",ans); 42 } 43 return 0; 44 }
貌似用母函数也可以求解这道题
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <iostream> 5 using namespace std; 6 7 int a[102], c[102]; 8 int c1[100002] = {0}; 9 int c2[100002] = {0}; 10 int ans[100002] = {0}; 11 int p; 12 int n, m; 13 14 void multi(int cn1, int cn2) { 15 cn1 = min(cn1, m); 16 cn2 = min(cn2, m); 17 for(int i = 0; i <= cn1; i++) { 18 for(int j = 0; j <= cn2; j++) { 19 ans[i+j] = ans[i+j] + c1[i]*c2[j]; 20 } 21 } 22 p = cn1 + cn2; 23 } 24 25 int main(int argc, char const *argv[]) 26 { 27 28 freopen("input.txt","r",stdin); 29 while(scanf("%d %d",&n,&m) != EOF && (n != 0 && m != 0)) { 30 for(int i = 1; i <= n; i++) { 31 scanf("%d",&a[i]); 32 } 33 for(int i = 1; i <= n; i++) { 34 scanf("%d",&c[i]); 35 } 36 memset(ans, 0, sizeof(ans)); 37 for(int i = 0; i <= c[1]; i++) { 38 ans[i*a[1]] = 1; 39 } 40 p = a[1]*c[1]; 41 for(int i = 2; i <= n; i++) { 42 memset(c1, 0, sizeof(c1)); 43 memset(c2, 0, sizeof(c2)); 44 for(int j = 0; j <= p; j++) { 45 c1[j] = ans[j]; 46 } 47 for(int j = 0; j <= c[i]; j++) { 48 c2[j*a[i]] = 1; 49 } 50 memset(ans, 0, sizeof(ans)); 51 multi(p,a[i]*c[i]); 52 } 53 int anss = 0; 54 for(int i = 1; i <= m; i++) { 55 if(ans[i] > 0) { 56 anss++; 57 } 58 } 59 printf("%d ",anss); 60 } 61 return 0; 62 }
但是超时了