JZOJ 5461 购物 —— 贪心
题目:https://jzoj.net/senior/#main/show/5461
贪心,原来想了个思路,优先选优惠价最小的 K 个,然后其他按原价排序遍历;
如果当前物品没选过,原价选上,如果选过,考虑把它换成原价,然后把优惠价最小的下一个选上;
但这样做是75分,没考虑 替换没选过的物品 和 比较替换后是否更优;
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; typedef long long ll; int const maxn=5e4+5; int n,K,cnt; ll m,ans; bool vis[maxn]; struct N{int w,t,id;bool operator < (const N &y) const{return w>y.w;} }p[maxn]; priority_queue<N>q; bool cmp(N x,N y){return x.t<y.t;} int main() {freopen("shopping.in","r",stdin);freopen("shopping.out","w",stdout);scanf("%d%d%lld",&n,&K,&m);for(int i=1;i<=n;i++)scanf("%d%d",&p[i].w,&p[i].t);sort(p+1,p+n+1,cmp);for(int i=1;i<=n;i++)p[i].id=i,q.push(p[i]);for(int i=1;i<=K&&i<=n;i++){ if(ans+p[i].t>m)break;vis[i]=1; cnt=i; ans+=p[i].t;}if(cnt==n){printf("%d\n",n); return 0;}while(q.size()){int x=q.top().id,w=q.top().w,t=q.top().t; q.pop();if(!vis[x]){if(ans+w>m)continue;ans+=w; cnt++; }else{if(ans-p[x].t+p[x].w+p[K+1].t>m)continue;ans=ans-p[x].t+p[x].w+p[K+1].t; K++; cnt++;vis[x]=0; vis[K]=1;}}printf("%d\n",cnt);return 0; }
原
正解是直接把选中物品的 原价 - 优惠价 放入小根堆,然后其他物品按原价排序,直接判断、替换;
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; typedef long long ll; int const maxn=5e4+5; int n,K,cnt; ll m,ans; bool vis[maxn]; struct N{int w,t,id;}p[maxn]; priority_queue<int>q; bool cmp(N x,N y){return x.t<y.t;} bool cmp2(N x,N y){return x.w<y.w;} int main() { // freopen("shopping.in","r",stdin); // freopen("shopping.out","w",stdout);scanf("%d%d%lld",&n,&K,&m);for(int i=1;i<=n;i++)scanf("%d%d",&p[i].w,&p[i].t),p[i].id=i;sort(p+1,p+n+1,cmp);for(int i=1;i<=K&&i<=n;i++){ if(ans+p[i].t>m)break;cnt=i; ans+=p[i].t; q.push(p[i].t-p[i].w); vis[p[i].id]=1;}if(cnt==n){printf("%d\n",n); return 0;}sort(p+1,p+n+1,cmp2);for(int i=1,x;i<=n;i++){if(vis[p[i].id])continue;if(q.size()){x=-q.top();if(x+p[i].t>p[i].w&&ans+p[i].w<=m)ans+=p[i].w,cnt++;else if(x+p[i].t<=p[i].w&&ans+x+p[i].t<=m)ans+=x+p[i].t,cnt++,q.pop(),q.push(p[i].t-p[i].w);}else if(ans+p[i].w<=m)ans+=p[i].w,cnt++;} printf("%d\n",cnt);return 0; }
TJ
但这样总感觉不对,因为按原价排序并不能保证替换最优;
这里就是反例:
6 3 15
10 3
8 4
7 5
5 1
4 2
3 2
按这样的做法,会先选后3个物品,然后按 1,2,3 把前三个物品排序;
然后把物品6换成原价购买,优惠价购买物品 3;
之后就不能买了,输出4;
但实际上应该是优惠价购买物品 1,2,4,原价购买物品 5,6,答案是5;
所以应该采用别的贪心策略,看到了一种很好的:https://blog.csdn.net/qq_40448823/article/details/81488195 (不过这篇博客贴错题面了囧)
所有物品都按优惠价排序,同时开了一个原价购买的大根堆,存已经原价买下的东西的原价;
先买 K 个优惠价的,然后从优惠价排序的顺序继续往后看,每次去掉优惠买中 原价 - 优惠价 最小的一个,优惠价买下一个;
然后回头看看能否原价买上去掉的这个东西,能就原价买上,不能就去原价物品堆里看看,如果能替换一下使花钱更少,那么就替换一下;
而如果优惠价购买下一个不如原价购买下一个优,那么原价购买下一个,同样进行替换的判断;
然后就能过掉上面的数据了,主要是因为优惠价部分排序满足,原价部分用大根堆替换来满足;
不过数据太水,也不知道这个做法是否完美无瑕,看样子应该没问题,先放到这里吧。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; typedef long long ll; int const maxn=50005; int n,K,ans; ll sum,m; struct N{int w,t,c;bool operator < (const N &y) const{return c>y.c;} }p[maxn]; priority_queue<N>Q; priority_queue<int>q; bool cmp(N x,N y){return x.t<y.t;} int main() {freopen("shopping.in","r",stdin);freopen("shopping.out","w",stdout);scanf("%d%d%lld",&n,&K,&m);for(int i=1;i<=n;i++)scanf("%d%d",&p[i].w,&p[i].t),p[i].c=p[i].w-p[i].t;sort(p+1,p+n+1,cmp);for(int i=1;i<=n;i++){if(Q.size()<K&&sum+p[i].t<=m){sum+=p[i].t; ans++; Q.push(p[i]);}//Q是按差价排序的堆 else if(Q.size()==K)//其他物品是按优惠价排序的 {N x=Q.top();if(x.c+p[i].t<=p[i].w)//优惠价购买较优 {Q.pop(); Q.push(p[i]); sum=sum-x.t+p[i].t;//先优惠价买上 if(sum+x.w<=m){sum+=x.w; ans++; q.push(x.w);}//可以原价买原来那个 //q是原价购买了的堆 else if(q.size()&&q.top()>x.w){sum=sum-q.top()+x.w; q.pop(); q.push(x.w);}//不能买了,换掉之前原价购买的一个物品,可以更优 }else if(sum+p[i].w<=m){sum+=p[i].w; ans++; q.push(p[i].w);}//原价购买 else if(q.size()&&q.top()>p[i].w){sum=sum-q.top()+x.w; q.pop(); q.push(x.w);}//不能买了,替换更优 }}printf("%d\n",ans);return 0; }
转载于:https://www.cnblogs.com/Zinn/p/9439885.html
JZOJ 5461 购物 —— 贪心相关推荐
- 第15届台州学院校赛题解
Red学编程 注意判断 ac个数 等于零的情况不要re #include<bits/stdc++.h> using namespace std; typedef long long ll; ...
- 【并查集】【最小生成树】【贪心】给水(jzoj 2015)
给水 jzoj 2015 题目大意: 有n个草地,可以在某些草地各安装一个水井,代价是aia_iai,或者从别的草地运水过来,代价是pijp_{ij}pij,现在问要让所有草地都有水,代价最少是多 ...
- 【贪心】逃跑(jzoj 1748)
逃跑 jzoj 1748 题目大意 你有一个能量值l,在接下来的n天里,你每天有两个选择: 1.增加l个食物 2.使l加一, 你第i天要吃ai个a_i个ai个食物,如果吃不到就会死掉,现在问你n天后 ...
- 【贪心】失意(jzoj 2318)
失意 jzoj 2318 题目大意: 在x轴上给出n条线段,让你选m条线段,使他们的相交部分尽量大 输入样例: 4 6 3 3 8 4 12 2 6 1 10 5 9 11 12 输出样例: 4 1 ...
- [二分][贪心]JZOJ P3996 Sabotage
Description FJ 的死对头,FP,现在决定了去破坏FJ 的挤奶设备! 这个挤奶设备由一行N(3 <= N<= 100, 000)个挤奶机器,其中第i 个机器生产Mi 单位的牛奶 ...
- 【jzoj 4727】【NOIP2015模拟10.28B组】终章-剑之魂 {贪心}
题目 Description [背景介绍] 古堡,暗鸦,斜阳,和深渊-- 等了三年,我独自一人,终于来到了这里-- "终焉的试炼吗?就在这里吗?"我自言自语道. "终焉的 ...
- [jzoj 1285] 奶酪厂 {贪心}
题目 Description 奶牛买了一个奶酪厂生产奶酪,已知每周生产一单位奶酪的费用为C_i,每周可以生产任意数量的奶酪,现在要为接下来N(1<=N<=10,000)周做生产计划. 厂里 ...
- [jzoj 4249] 【五校联考7day1】游戏 {贪心/斜率优化}
题目 Description WYF从小就爱乱顶,但是顶是会造成位移的.他之前水平有限,每次只能顶出k的位移,也就是从一个整点顶到另一个整点上.我们现在将之简化到数轴上,即从 一个整点可以顶到与自己相 ...
- P1658 购物(贪心算法)
P1658 购物 提交 2.48k 通过 1.16k 时间限制 1.00s 内存限制 125.00MB 题目描述 你就要去购物了,现在你手上有N种不同面值的硬币,每种硬币有无限多个.为了方便购物,你希 ...
最新文章
- Dos攻击工具(ZAmbIE)
- SQL Server 2005系列教学(2) SQL 服务及创建数据库
- 倒车辅助Park Assist
- 如何做流数据分析,Byron Ellis来告诉你...
- “内卷化”的快手与抖音——2020年短视频的“无聊经济”往何处去
- 在有限多的不大于100的正整数中,找出尽量多个相加起来值介于98~102之间的组合...
- [SDOI2016] 生成魔咒(后缀数组SA + st表 + set)动态不同子串个数
- go结构体初始化_golang中结构体的初始化方法
- JNI读取assets资源文件
- 训练赛20160403
- 如何把图纸转换为t3格式_天正cad转t3格式
- linux服务器什么意思,linux中的“/”和“./”是什么意思
- 快速推导出等比数列的求和公式
- python爬虫学习笔记 3.9 (了解参考:训练Tesseract)
- windows内核开发学习笔记十五:IRP结构
- php实现新浪微博分享功能,自定义新浪微博分享按钮样式
- 液压管路渗漏图像识别检测方法研究
- 电力电子技术填空题(80+道),适合期末复习、面试等
- 【转载】干簧管小贴士
- 《MySQL数据库》之练习表数据:emp表与dept表的脚本整理