HDU 6092 Rikka with Subset(完全背包)

来源:互联网 发布:下载淘宝助理免费 编辑:程序博客网 时间:2024/05/16 23:47

强行解释题解见:http://blog.csdn.net/mirror58229/article/details/76998556
这个题可以联想到钱币兑换问题,即用前i种货币兑换成j的方案数。
对于一个i,这个i在A中的个数为 b[i]-用已有的钱币兑换成i的数量;
后面就可以直接用钱币兑换中的dp方程递推出结果。
dp方程中的结果是逆向增加的,因为如果正向增加就会出现已经覆盖的结果。

如正向时对于样例1 1 1 1的第一次操作
dp[1] = dp[1] + dp[0] = 1
dp[2] = dp[2] + dp[1] = 1
dp[3] = dp[3] + dp[2] = 1
而实际的反向情况是
dp[3] = dp[3] + dp[2] = 0
dp[2] = dp[2] + dp[1] = 0
dp[1] = dp[1] + dp[0] = 1

因为钱币兑换的后一种结果是可以包括前一种结果的
但这题的用已有的钱币兑换i是单纯地用钱币兑换i 不包括之前的兑换方法

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <vector>#include <queue>#include <cmath>using namespace std;const int N = 1E4 + 10;typedef long long ll;ll b[N];ll a[55];ll dp[N];int main(){    int t;    scanf("%d", &t);    while(t--){        int n, m;        scanf("%d %d", &n, &m);        for(int i = 0; i <= m; i++){            scanf("%lld", &b[i]);        }        int cnt = 0;        memset(dp, 0, sizeof(dp));        dp[0] = 1;        for(ll i = 1; i <= m; i++){            if(b[i]){                if(cnt == n) break;                int num = b[i] - dp[i];                for(ll j = 0; j < num; j++){                    a[cnt++] = i;                    for(ll k = m; k >= i; k--){                        dp[k] += dp[k - i];                    }                }            }        }        for(int i = 0; i < cnt; i++){            if(i == cnt - 1) printf("%lld\n", a[i]);            else printf("%lld ", a[i]);        }    }}
原创粉丝点击