hdu6092(dp)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6092

 

题意: 输入格式为, 对于每组测试样例第一行输入两个数 n, m, 接下来一行输入B数组, 有 m + 1个数. 其中 n 表示要构造的数组 A 的长度为 n. m 表示 A 数组的元素和为 m. 第二行的m + 1 个数字表示 A 数组 有子集中和为 0, 1, ..., m 的子集个数.

 

思路: 可以从 1 到 m 依次确定每个数出现的次数. 用 dp[i] 表示当前答案集中和为 i 的子集数.

枚举 1 <= i <= m, 对于当前 i, 其在 A 中出现的次数为 B[i] - dp[i], 每往 A 中添加一个元素更新一次 dp 数组.

更新 dp 的过程可以看作一个 01 背包过程.

 

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 using namespace std;
 5 
 6 const int MAXN = 1e4 + 10;
 7 int dp[MAXN], a[MAXN], sol[MAXN];//dp[i]存储当前答案集中和为i的子集有多少
 8 
 9 int main(void){
10     int t, n, k;
11     scanf("%d", &t);
12     while(t--){
13         int indx = 0;
14         memset(dp, 0, sizeof(dp));
15         scanf("%d%d", &n, &k);
16         for(int i = 0; i <= k; i++){
17             scanf("%d", &a[i]);
18         }
19         dp[0] = 1;
20         for(int i = 1; i <= k; i++){
21             int cnt = a[i] - dp[i];
22             for(int j = 0; j < cnt; j++){
23                 sol[indx++] = i;
24                 for(int l = k; l >= i; l--){//注意先更新小的数会影响后面的更新
25                     dp[l] += dp[l - i];
26                 }
27             }
28         }
29         for(int i = 0; i < indx; i++){
30             if(i) printf(" ");
31             printf("%d", sol[i]);
32         }
33         puts("");
34     }
35     return 0;
36 }
View Code

 

posted @ 2017-08-09 16:21  geloutingyu  阅读(253)  评论(0编辑  收藏  举报