poj3260解题报告

来源:互联网 发布:教练技术 知乎 编辑:程序博客网 时间:2024/06/10 13:04

题目大意:

农夫John想到镇上买些补给。为了高效地完成任务,他想使硬币的转手次数最少。即使他交付的硬 币数与找零得到的的硬币数最少。 John想要买T(1<=T<=10000)样东西。有N(1<=n<=100)种货币参与流通,面值分别为V1,V2..Vn (1<=Vi<=120)。John有Ci个面值为Vi的硬币(0<=Ci<=10000)。我们假设店主有无限多的硬币, 并总按最优方案找零。

解题思路:

先来一次多重背包,上限要比t大才行,因为可以找钱,再来一发完全背包,因为找钱这个时候货币是无限的

代码:

#include<cstdio>
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=30000;
const int INF= 100000000;
int n,t,val[110],c[110],d[maxn],MAX,k,i,j;
int main()
{
           //freopen("1.txt","r",stdin);
           while(~scanf("%d%d",&n,&t))
    {
        MAX = 0;
        for(i=1; i<=n; i++)
        {
            scanf("%d",&val[i]);
            MAX = max(MAX,val[i]);
        }
        MAX*=MAX;
        for(i=1; i<=n; i++)
            scanf("%d",&c[i]);
                 for(i = 1; i<=t+MAX; i++)//初始化
                        d[i] = INF;
                d[0] = 0;
                for( i=1;i<=n;i++)//多重背包二进制优化法
                {
                        k=1;
                        while(k<c[i])
                       {
                                  for(j = t+MAX; j>=k*val[i]; j--)
                                        d[j] = min(d[j],d[j-k*val[i]]+k);
                                c[i]-=k;
                                k=k*2;
                       }
                        for(j=MAX+t;j>=c[i]*val[i];j-- )
                                        {d[j]=min(d[j],d[j-c[i]*val[i]]+c[i]);}
                }
                 for( i=1;i<=n;i++)//完全背包找钱
                          for(j = t+MAX-val[i]; j>=0; j--)
                                d[j] = min(d[j],d[j+val[i]]+1);
                if(d[t]==INF)  cout<<-1<<endl;
                 else  cout<<d[t]<<endl;
           }
}


1 0
原创粉丝点击