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

来源:互联网 发布:三国志12全武将数据 编辑:程序博客网 时间:2024/04/29 14:23

链接:poj 3260

题意FJ同学去买东西,东西的价值为T,他和卖家都有N种金币,FJ希望交易完成时金币变化最小。

求最少的金币变化数量。FJ的金币个数有限,卖家的金币数目无限。

思路背包问题,FJ的每种金币个数有限可以看做是多重背包问题,卖家的金币数目无限可以看做是完全背包问题。

设F1[i]为FJ付款为i时的最小金币数,设F2[i]为卖家找钱为i时的最小金币数。

则F1[i+T]+F2[i]就是所求的最小金币变化数量(F1用多重背包求解,F2用完全背包求解)

PS:这里的背包求得是最小价值,且要恰好装满。故初始化数组时应 F[0]=0,F[1~MAXN]=INT_MAX;

#include<stdio.h>#define INF 9999999int f1[1000010],f2[1000010],v;int min(int a,int b){    return a<b?a:b;}void zeroone(int cost,int weight,int *f)   //01背包{    int i;    for(i=v;i>=cost;i--)        f[i]=min(f[i],f[i-cost]+weight);}void complete(int cost,int weight,int *f)        //完全背包{    int i;    for(i=cost;i<=v;i++)        f[i]=min(f[i],f[i-cost]+weight);}void multiple(int num,int cost,int weight,int *f)   //多重背包{    int k;    if(num*weight>=v){        complete(cost,weight,f);        return ;    }    for(k=1;k<num;k*=2){        zeroone(k*cost,k*weight,f);        num-=k;    }    zeroone(num*cost,num*weight,f);}int main(){    int i,T,max,n,num[110],c[110],k;    while(scanf("%d%d",&n,&T)!=EOF){        max=0;        for(i=1;i<=n;i++){            scanf("%d",&c[i]);            if(c[i]>max)                max=c[i];        }        for(i=1;i<=n;i++)            scanf("%d",&num[i]);        v=max*max+T;                     //因为要找钱,v要比T大很多、、、        f1[0]=f2[0]=0;        for(i=1;i<=v;i++)            f1[i]=f2[i]=INF;        for(i=1;i<=n;i++)            multiple(num[i],c[i],1,f1);        for(i=1;i<=n;i++)            complete(c[i],1,f2);        k=INF;        for(i=0;i<=v-T;i++)            if(f1[i+T]!=INF&&f2[i]!=INF)                k=min(k,f1[i+T]+f2[i]);        if(k==INF)            k=-1;        printf("%d\n",k);    }    return 0;}


2 3
原创粉丝点击