poj 3260 The Fewest Coins 多重背包+完全背包

题目链接:http://poj.org/problem?id=3260

 

给店家的钱是多重背包 dp[]

店家的找钱是完全背包 dp2[]

 

然后最后 其中i表示多给了多少钱 也就是需要找回多少钱 

int ans = INF;

ans = min(ans, dp[m+i] + dp2[i]);

是一个比较简单的思路

 

神坑题 

看到每种货币的面值不大于120 我就觉得找钱一定不会超过119块钱结果wa到死

后来才发现不是的啊

之所以我有这种思维定式是因为现实生活中有1块钱这种货币单位

考虑一种极限的情况

只有面值为120元、119元两种货币

然后你只有120那种 要去买价值为120*82 + 119 = 9959元的东西

那119的部分需要你给店家119张120块钱让他找你119张119块钱Orz 【三观啊...

这样一来可以大概估计找钱的一个上界是14400

 

所以两个DP过程的容量都加上14400然后再去做就能过T^T

 

另外写CompletePack2()的时候我明明没有改V的值可是V的值变了

后来才反应过来这种事情很可能就是数组越界

检查了一下果然边界情况没有控制好

 

 

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <stack>
#include <set>
#include <queue>
#include <vector>

using namespace std;

typedef long long ll;

const int maxn = 110;
const int maxm = 10200;
const int INF = 100000;

int a[maxn], c[maxn];
int dp[maxm + 15000];
int dp2[15000];
int V;

void ZeroOnePack(int cost, int weight)
{
    for(int i = V; i >= cost; i--)
    {
        dp[i] = min(dp[i], dp[i-cost] + weight);
    }
}

void CompletePack(int cost, int weight)
{
    for(int i = cost; i <= V; i++)
    {
        dp[i] = min(dp[i], dp[i-cost] + weight);
    }
}

void MultiplePack(int cost, int weight, int amount)
{
    if(cost*amount >= V)
    {
        CompletePack(cost, weight);
        return;
    }
    int k = 1;
    while(k < amount)
    {
        ZeroOnePack(k*cost, k*weight);
        amount = amount - k;
        k *= 2;
    }
    ZeroOnePack(amount*cost, amount*weight);
}

void CompletePack2(int cost, int weight)
{
    for(int i = cost; i < V; i++)
    {
        dp2[i] = min(dp2[i], dp2[i-cost] + weight);
    }
}

int main()
{
    //freopen("in.txt", "r", stdin);

    int n, m;

    while(scanf("%d%d", &n, &m) == 2)
    {
        memset(dp, 0x3f, sizeof(dp));
        memset(dp2, 0x3f, sizeof(dp2));
        dp[0] = dp2[0] = 0;

        for(int i = 0; i < n; i++)
            scanf("%d", &a[i]);

        for(int i = 0; i < n; i++)
            scanf("%d", &c[i]);

        V = m + 14400;
        for(int i = 0; i < n; i++)
            MultiplePack(a[i], 1, c[i]);

        V = 14400;
        for(int i = 0; i < n; i++)
        {
            CompletePack2(a[i], 1);
        }

        int ans = INF;
        for(int i = 0; i < 14400; i++)
        {
            ans = min(ans, dp[m+i] + dp2[i]);
        }

        if(ans == INF)
            printf("-1\n");
        else
            printf("%d\n", ans);
    }

    return 0;
}

 

posted @ 2015-02-19 12:08  地鼠地鼠  阅读(146)  评论(0编辑  收藏  举报