andre_joy

导航

poj 3260

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

题意:有Vi种硬币,每个硬币有Ci个,要付的价钱T,付多了,老板会找钱,用已有的硬币种类找,求给的和找的硬币数量最少的方案。

mark:多重背包,可以参照我的另外一篇日志http://www.cnblogs.com/andre0506/archive/2012/09/22/2697788.html来优化,效率是O(NV)。

   这种方法必须排序!

代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct
{
    int v,c;
}ss;

const int INF = 1000000;
const int N = 30000;
const int M = 150;
int n,t,vmax,cnt;
ss s[M];
int d[M*M],dp[N],used[N], min1[N];

int min(int a, int b) {return a < b ? a : b;}

int cmp(const void *a, const void *b)
{
    return (*(ss *)b).v - (*(ss *)a).v;
}

void init()
{
    int i,j;
    for(i = 1; i < vmax*vmax; d[i++] = INF);
    d[0] = 0;
    for(i = 0; i < n; i++)
        for(j = s[i].v; j < vmax*vmax; j++)
            d[j] = min(d[j], d[j-s[i].v]+1);
}

int main()
{
    int i,j,k;
    while(~scanf("%d%d", &n, &t))
    {
        vmax = 0;
        for(i = 0; i < n; i++)
        {
            scanf("%d", &s[i].v);
            if(s[i].v > vmax) vmax = s[i].v;
        }
        for(i = 0; i < n; i++)
            scanf("%d", &s[i].c);
        qsort(s, n, sizeof(ss), cmp);
        init();
        for(i = 1; i < t+vmax*vmax; i++)
            dp[i] = min1[i] = INF;
        dp[0] = 0;
        for(i = 0; i < n; i++)
        {
            memset(used, 0, sizeof(used));
            for(j = s[i].v; j < t+vmax*vmax; j++)
            {
                if(dp[j-s[i].v]+1 < dp[j] && used[j-s[i].v] < s[i].c)
                {
                    dp[j] = dp[j-s[i].v]+1;
                    used[j] = used[j-s[i].v]+1;
                    if(j >= t && d[j-t] != INF) min1[j] = dp[j]+d[j-t];
                }
            }
        }
        cnt = INF;
        for(i = t; i < t+vmax*vmax; i++)
            cnt = min(cnt, min1[i]);
        printf("%d\n", cnt == INF ? -1 : cnt);
    }
    return 0;
}

posted on 2012-09-24 12:14  andre_joy  阅读(358)  评论(0编辑  收藏  举报