POJ3260_The Fewest Coins_deque优化dp解多重背包和完全背包

题意

拿着 n 种硬币,每种硬币面值 vi,数量 ci,去商店购买价值 t 的物品。商店也同样有这些种类的硬币,但数目无限。问付钱和找零的过程中,至少 需要多少个硬币。

思路

付钱是多重背包,找零是完全背包。
有意思的地方是付款金额的上界问题,网上证明了 maxv * maxv + t。然而证明过程一知半解。其实猜一猜也就过了。

链接

http://poj.org/problem?id=3260

代码

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int maxn = 100 + 10;
const int maxv = 1e5 + 10;
const int inf = 0x3f3f3f3f;

int n, T, sum;
int V[maxn], C[maxn];
int dp[maxv], dp1[maxv];
int deq[maxv], deqv[maxv];

void solve(int *dp){
    dp[0] = 0;

    for(int i = 0; i < n; i++){
        for(int a = 0; a < V[i]; a++){
            int s = 0, t = 0;
            for(int j = 0; j * V[i] + a <= sum; j++){
                int val = dp[j * V[i] + a] - j;
                while(s < t && deqv[t - 1] >= val) t--;
                deq[t] = j;
                deqv[t++] = val;
                dp[j * V[i] + a] = deqv[s] + j;

                if(deq[s] == j - C[i]){
                    s++;
                }
            }
        }
    }
}

int main(){
    scanf("%d %d", &n, &T);
    for(int i = 0; i < n; i++){
        scanf("%d", V + i);
    }
    for(int i = 0; i < n; i++){
        scanf("%d", C +i);
    }

    sum = 1e5;

    memset(dp, inf, sizeof dp);
    solve(dp);

    memset(C, inf, sizeof C);
    memset(dp1, inf, sizeof dp1);
    solve(dp1);

    int res = inf;
    for(int i = T; i <= sum; i++){
        res = min(res, dp1[i - T] + dp[i]);
    }

    if(res >= 10000) printf("-1\n");
    else printf("%d\n", res);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值