poj1742(多重背包dp)

来源:互联网 发布:乐知英语的公司在哪 编辑:程序博客网 时间:2024/03/29 02:42

点击打开链接

/*translation:给定一些硬币面额以及对应的个数,求用这些硬币可以拼凑成多少种不同数值的金额。solution:多重背包dp这道题必须用多重背包dp的可行性类型O(nm)复杂度的算法来求解。设dp[i][j]:前i种拼凑出面值恰好为j时,最多还剩下几个第i种的硬币先将所有初始化为-1.则dp[i][j]>=0dp[i+1][j] = c[i].j<a[i] || dp[i+1][j-a[i]]<=0dp[i+1][j] = -1剩下其他条件下dp[i+1][j] = dp[i + 1][j - a[i]] - 1note:1:一开始考虑用二进制拆分背包来求解,但是TLE了,改为O(nm)复杂度的算法竟然就过了!2:原先是这样定义状态方程的,dp[i]为前i种能够拼凑成不同重量的种数,但不管怎么加状态参数等还是无法满足无后效性。所以有些问题思路不能僵化,不一定要死死对“原问题”求解。可以像这到题采取“曲线救国”。求某种重量能否满足,最后以线性时间内暴力将所有重量清点出来,还是可以满足时间限制的!date:2016.9.2*/#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int maxn = 105;const int maxm = 100005;int a[maxn], c[maxn];//面值以及想对应的个数int n, m;//不同币值的种类数,最多不能超过多少钱int dp[maxm];//表示用前i种物品填满容量为j的背包后,最多还剩下几个第i中物品可以用int main(){//freopen("in.txt", "r", stdin);    while(~scanf("%d%d", &n, &m) && n) {for(int i = 0; i < n; i++)scanf("%d", &a[i]);for(int i = 0; i < n; i++)scanf("%d", &c[i]);memset(dp, -1, sizeof(dp));dp[0] = 0;//实际实现过程用滚动数组来实现for(int i = 0; i < n; i++) {for(int j = 0; j <= m; j++) {if(dp[j] >= 0)dp[j] = c[i];else if(j < a[i] || dp[j - a[i]] <= 0)dp[j] = -1;elsedp[j] = dp[j - a[i]] - 1;}}int cnt = 0;for(int i = 1; i <= m; i++)if(dp[i] >= 0)cnt++;printf("%d\n", cnt);    }    return 0;}


0 0
原创粉丝点击