luogu P2918 [USACO08NOV]买干草Buying Hay

在这里插入图片描述

analysis


我的思路
这道题第一眼看,是个完全背包
但是是求最小值?
hm&%&*@#!%&%^$…………
不如这样,把干草磅数作为收益,花销作为体积,再套一个完全背包模板
但是这个花销上限是多少??

!#@!##&%&@#!%&_%$…………

假设每个公司买一磅5000美元,那么最大开销就可能达到25000000美元…

!#@!##&%&@#!%#&%&@#!%&*_%^$…………

通过暴力二分,终于发现假设最大开销为225000勉强在本地上跑得过,于是就侥幸AC了
总感觉有点什么不对



题解的思路
嗯,完全背包,求最小值,还是设花销为收益,磅数为体积,只是改下方程
f [ i ] = m i n ( f [ i ] , f [ i − v [ j ] ] + w [ j ] ) f[i]=min(f[i],f[i-v[j]]+w[j]) f[i]=min(f[i],f[iv[j]]+w[j])
然后初值设一个-inf
由于是采购至少H磅干草,那么就有可能需要采购稍微多H磅但是多不过5000,因为如果多过5000,那么必定可以少买一次使得买到的磅数大于H且花费要少些
嗯,可以AC了


ε=(´ο`*)))唉,完虐啊

code

我的思路

#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define ll long long 
ll h,n;
const int maxh=50000+10,maxn=100+10;
ll P[maxn],C[maxn];
const int maxc=500*500+10;
ll f[maxc];
inline ll DP(int V){
    clean(f,0);
    loop(i,1,n){
        loop(j,C[i],V){
            f[j]=max(f[j],f[j-C[i]]+P[i]);
        }
    }
    loop(i,1,V)
        if(f[i]>=h)return i;
}
int main(){
    //freopen("datain.txt","r",stdin);
    clean(P,0),clean(C,0);
    scanf("%lld%lld",&n,&h);
    loop(i,1,n)scanf("%lld%lld",&P[i],&C[i]);
    printf("%lld\n",DP(225000));
    return 0;
}

题解的思路(巨佬可以忽略逗比注释)

#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define ll long long 
ll h,n;
const int maxh=50000+10,maxn=100+10;
ll P[maxn],C[maxn];
const int maxc=50000+5000+10;
ll f[maxc];
inline ll DP(){
    clean(f,0x3f);f[0]=0; 
    loop(i,1,n){//f[i]指刚刚采购i磅干草的最小价格 
    	loop(j,P[i],h+5000){//1.P[i]是因为第i个物品最小可以凑出P[i] 2.h+5000是因为若不能够刚刚凑出h磅,那么下一个可以凑出来的最优的数必然在h+5000以内 
            f[j]=min(f[j],f[j-P[i]]+C[i]);
        } 
    }
    /*loop(i,h,h+5000)
        if(f[i]<9187201950435737471)
            return f[i];*/
    //这样写是错的,因为可能你多买一点比你少买一点还便宜
    ll res=LONG_LONG_MAX;
    loop(i,h,h+5000)
        res=min(res,f[i]);
    return res;
}
int main(){
    //freopen("datain.txt","r",stdin);
    clean(P,0),clean(C,0);
    scanf("%lld%lld",&n,&h);
    loop(i,1,n)scanf("%lld%lld",&P[i],&C[i]);
    printf("%lld\n",DP());
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AndrewMe8211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值