[Usaco2008 Nov]Buying Hay 购买干草

题目描述

约翰的干草库存已经告罄,他打算为奶牛们采购H(1≤H≤50000)磅干草,他知道N(1≤N≤100)个干草公司,现在用1到N给它们编号。第i个公司卖的干草包重量为Pi(1≤Pi≤5000)磅,需要的开销为Ci(l≤Ci≤5000)美元.每个干草公司的货源都十分充足,可以卖出无限多的干草包.帮助约翰找到最小的开销来满足需要,即采购到至少H磅干草.

输入格式

第1行输入N和H,之后N行每行输入一个Pi和Ci.

输出格式

最小的开销.


与普通的完全背包不同的是,这题装的干草可以超过所需的重量。这里介绍两种常见的做法。

1.把背包总体积往上扩一段,也就是把背包容量扩大。设此时的容量为m'。然后做完全背包即可。最后枚举m~m'的每一位,取最小代价。由于题中的Pi≤5000,所以让m'等于m+5000即可。

2.刷表法。设当前已经买了j磅的干草,已经买了i-1种干草,每种干草的重量为ci、价格为vi。那么:

\[ dp[j+c[i]]=Min(dp[j+c[i]],dp[j]+v[i]) \]

如果j+c[i]>m,那么直接计算到dp[m]的头上即可。所以把算式微调一下,改为:

\[ dp[Min(j+c[i],m)]=Min(dp[Min(j+c[i]),m],dp[j]+v[i]) \]

第一种的时间复杂度为O(N(M+Max{ci}));第二种为O(NM)。实际上跑得差不多快。

第二种的代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 101
#define maxm 50001
using namespace std;
 
int dp[maxm],c[maxn],v[maxn];
int n,m;
 
inline int read(){
    register int x(0),f(1); register char c(getchar());
    while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
    while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
 
int main(){
    n=read(),m=read();
    for(register int i=1;i<=n;i++) c[i]=read(),v[i]=read();
 
    memset(dp,0x3f,sizeof dp);
    dp[0]=0;
    for(register int i=1;i<=n;i++){
        for(register int j=0;j<=m;j++){
            dp[min(j+c[i],m)]=min(dp[min(j+c[i],m)],dp[j]+v[i]);
        }
    }
    printf("%d\n",dp[m]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/akura/p/10864467.html