POJ 1742 Coins

明显dp题,但是如何高效dp则是个问题;
令dp[i][j]表示用前i种硬币表示面值j时第i种硬币最多能剩多少个,那么,
1.如果dp[i-1][j]>=0,也就是前i-1种就能拼出j的话,那么dp[i][j]自然就是c[i]了;
2.如果j < a[i](第i种的面值)或者dp[i][j-a[i]]<=0(j比a[i]小或者用前i种根本就拼不出j-a[i]),则dp[i][j]=-1;
3.剩下的,dp[i][j]=dp[i][j-a[i]]-1;
同时注意到当前状况仅与上一次的状态有关,故可压缩i;
每次循环j从小到大,这样的话,就可以保证1中的dp[j]是上一次循环的值而2,3中的dp[j-a[i]]为本次循环后的值。
最后,注意j必须从0开始!!!

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
    int n, m, i, j, k;
    int f[100005], a[105], c[105];
    while (cin >> n >> m && n) {
        for (i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        for (i = 1; i <= n; i++)
            scanf("%d", &c[i]);
        memset(f, -1, sizeof(f));
        f[0] = 0;//初始化,f[0][0]=0;
        for (i = 1; i <= n; i++) 
            for (j = 0; j <= m; j++) {//从0开始!!!
                if (f[j] >= 0)//如果[i-1][j]>=0
                    f[j] = c[i];
                else if (j < a[i] || f[j - a[i]] <= 0)//如果f[i][j-a[i]]<=0,注意这里的f[j-a[i]]代表的是本次循环的值!!!
                    f[j] = -1;
                else {
                    f[j] = f[j - a[i]] - 1;
                }
            }
        int cnt = 0;
        for (i = 1; i <= m; i++)
            if (f[i] >= 0)cnt++;
        cout << cnt << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值