题目: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 购物 —— 贪心相关推荐

  1. 第15届台州学院校赛题解

    Red学编程 注意判断 ac个数 等于零的情况不要re #include<bits/stdc++.h> using namespace std; typedef long long ll; ...

  2. 【并查集】【最小生成树】【贪心】给水(jzoj 2015)

    给水 jzoj 2015 题目大意: 有n个草地,可以在某些草地各安装一个水井,代价是aia_iai​,或者从别的草地运水过来,代价是pijp_{ij}pij​,现在问要让所有草地都有水,代价最少是多 ...

  3. 【贪心】逃跑(jzoj 1748)

    逃跑 jzoj 1748 题目大意 你有一个能量值l,在接下来的n天里,你每天有两个选择: 1.增加l个食物 2.使l加一, 你第i天要吃ai个a_i个ai​个食物,如果吃不到就会死掉,现在问你n天后 ...

  4. 【贪心】失意(jzoj 2318)

    失意 jzoj 2318 题目大意: 在x轴上给出n条线段,让你选m条线段,使他们的相交部分尽量大 输入样例: 4 6 3 3 8 4 12 2 6 1 10 5 9 11 12 输出样例: 4 1 ...

  5. [二分][贪心]JZOJ P3996 Sabotage

    Description FJ 的死对头,FP,现在决定了去破坏FJ 的挤奶设备! 这个挤奶设备由一行N(3 <= N<= 100, 000)个挤奶机器,其中第i 个机器生产Mi 单位的牛奶 ...

  6. 【jzoj 4727】【NOIP2015模拟10.28B组】终章-剑之魂 {贪心}

    题目 Description [背景介绍] 古堡,暗鸦,斜阳,和深渊-- 等了三年,我独自一人,终于来到了这里-- "终焉的试炼吗?就在这里吗?"我自言自语道. "终焉的 ...

  7. [jzoj 1285] 奶酪厂 {贪心}

    题目 Description 奶牛买了一个奶酪厂生产奶酪,已知每周生产一单位奶酪的费用为C_i,每周可以生产任意数量的奶酪,现在要为接下来N(1<=N<=10,000)周做生产计划. 厂里 ...

  8. [jzoj 4249] 【五校联考7day1】游戏 {贪心/斜率优化}

    题目 Description WYF从小就爱乱顶,但是顶是会造成位移的.他之前水平有限,每次只能顶出k的位移,也就是从一个整点顶到另一个整点上.我们现在将之简化到数轴上,即从 一个整点可以顶到与自己相 ...

  9. P1658 购物(贪心算法)

    P1658 购物 提交 2.48k 通过 1.16k 时间限制 1.00s 内存限制 125.00MB 题目描述 你就要去购物了,现在你手上有N种不同面值的硬币,每种硬币有无限多个.为了方便购物,你希 ...

最新文章

  1. Dos攻击工具(ZAmbIE)
  2. SQL Server 2005系列教学(2) SQL 服务及创建数据库
  3. 倒车辅助Park Assist
  4. 如何做流数据分析,Byron Ellis来告诉你...
  5. “内卷化”的快手与抖音——2020年短视频的“无聊经济”往何处去
  6. 在有限多的不大于100的正整数中,找出尽量多个相加起来值介于98~102之间的组合...
  7. [SDOI2016] 生成魔咒(后缀数组SA + st表 + set)动态不同子串个数
  8. go结构体初始化_golang中结构体的初始化方法
  9. JNI读取assets资源文件
  10. 训练赛20160403
  11. 如何把图纸转换为t3格式_天正cad转t3格式
  12. linux服务器什么意思,linux中的“/”和“./”是什么意思
  13. 快速推导出等比数列的求和公式
  14. python爬虫学习笔记 3.9 (了解参考:训练Tesseract)
  15. windows内核开发学习笔记十五:IRP结构
  16. php实现新浪微博分享功能,自定义新浪微博分享按钮样式
  17. 液压管路渗漏图像识别检测方法研究
  18. 电力电子技术填空题(80+道),适合期末复习、面试等
  19. 【转载】干簧管小贴士
  20. 《MySQL数据库》之练习表数据:emp表与dept表的脚本整理

热门文章

  1. 合并两个有序数组(重新开始)
  2. 十一运夺金基础数据采集工具
  3. FRAME与IFRAME
  4. Ajax检测注册用户是否存在
  5. usaco Combination Lock
  6. php mysql函数未定义,PHP MySQLi未定义的方法错误
  7. java语言环境变量_JAVA语言环境变量的设置教程
  8. linux中文麻酱字_【树】Linux笔记 1
  9. java jdk下载安装_Java JDK下载安装及配置
  10. 烟台大学计算机专业录取分数线,2017烟台大学录取分数线排行榜