题目: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+;
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=;i<=n;i++)scanf("%d%d",&p[i].w,&p[i].t);
sort(p+,p+n+,cmp);
for(int i=;i<=n;i++)p[i].id=i,q.push(p[i]);
for(int i=;i<=K&&i<=n;i++)
{
if(ans+p[i].t>m)break;
vis[i]=; cnt=i; ans+=p[i].t;
}
if(cnt==n){printf("%d\n",n); return ;}
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+].t>m)continue;
ans=ans-p[x].t+p[x].w+p[K+].t; K++; cnt++;
vis[x]=; vis[K]=;
}
}
printf("%d\n",cnt);
return ;
}

正解是直接把选中物品的 原价 - 优惠价 放入小根堆,然后其他物品按原价排序,直接判断、替换;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
int const maxn=5e4+;
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=;i<=n;i++)scanf("%d%d",&p[i].w,&p[i].t),p[i].id=i;
sort(p+,p+n+,cmp);
for(int i=;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]=;
}
if(cnt==n){printf("%d\n",n); return ;}
sort(p+,p+n+,cmp2);
for(int i=,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 ;
}

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=;
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=;i<=n;i++)scanf("%d%d",&p[i].w,&p[i].t),p[i].c=p[i].w-p[i].t;
sort(p+,p+n+,cmp);
for(int i=;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 ;
}

JZOJ 5461 购物 —— 贪心的更多相关文章

  1. JZOJ 5461. 【NOIP2017提高A组冲刺11.8】购物

    5461. [NOIP2017提高A组冲刺11.8]购物 (File IO): input:shopping.in output:shopping.out Time Limits: 1000 ms   ...

  2. JZOJ 5459 购物

    Description X 城的商场中,有着琳琅满目的各种商品.一日,小X 带着小Y 前来购物,小Y 一共看中了n件商品,每一件商品价格为Pi.小X 现在手中共有m个单位的现金,以及k 张优惠券.小X ...

  3. JZOJ.1150【贪心算法】IQ

    欢迎转载,请附上原链接https://www.cnblogs.com/Code-Garden/p/11276741.html(也没人会看) 一道对我来说较难的贪心题 题目描述 根据世界某权威学会的一项 ...

  4. JZOJ.1153【贪心算法】硬币交换

    好难啊!!! 可聪明的我还是解出来了!(逃 题目描述 小z最近迷上了一款游戏――To Be A Farmer,他在游戏中控制的人物是一个叫FZ的Farmer.FZ身上有G1个金币.S1个银币和B1个铜 ...

  5. JZOJ 1154. 【GDOI2003】购物

    1154. [GDOI2003]购物 (Standard IO) Time Limits: 1000 ms Memory Limits: 65536 KB Description GDOI商场推出优惠 ...

  6. [jzoj 4879] [NOIP2016提高A组集训第11场11.9] 少女觉 解题报告 (贪心)

    题目链接: http://172.16.0.132/senior/#main/show/4879 题目: 在幽暗的地灵殿中,居住着一位少女,名为古明地觉.据说,从来没有人敢踏入过那座地灵殿,因为人们恐 ...

  7. JZOJ 4611. 【NOI2016模拟7.11】接水问题 (贪心+A*+可持久化线段树)

    Description: https://gmoj.net/senior/#main/show/4611 题解: 先把A从大到小排序,最小的由排序不等式显然. 考虑类似第k短路的A*的做法. 定义状态 ...

  8. [jzoj]1729.blockenemy

    Link https://jzoj.net/senior/#main/show/1729 Description 你在玩电子游戏的时候遇到了麻烦...... 你玩的游戏是在一个虚拟的城市里进行,这个城 ...

  9. 洛谷P1658 购物

    题目戳 题目描述 你就要去购物了,现在你手上有N种不同面值的硬币,每种硬币有无限多个.为了方便购物,你希望带尽量少的硬币,但要能组合出1到X之间的任意值. 输入输出格式 输入格式: 第一行两个数X.N ...

随机推荐

  1. 如何创建TWaver 3D的轮廓选中效果

    在一般的游戏中,物体的选中效果会是这样: TWaver 3D中,物体的默认的选中效果一般都是一个方方正正的外框.在HTML5的Mono版本中,TWaver提供了轮廓线样式的选中效果. 通过如下代码把几 ...

  2. Bat 脚本(常用命令)

    Bat 批处理脚本 (常用) Bat 批处理脚本 === Content === 1. Rem 和 :: Rem 为注释命令,能回显. :: 为符号注释,不能回显. %行内注释内容% ===== (不 ...

  3. js之DOM间接操作

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. Python 实现批量查询IP并解析为归属地

    一.背景: 最近工作中做了一个小功能,目的是为了分析注册用户区域分布和订单的区域分布情况.所以需要将其对应的IP信息解析为归属地,并同步每天同步更新.线上跑起来效率还是有优化的空间,优化的方向:在调用 ...

  5. 06 Python流程控制

    目录: 12) if语句 13) 三目运算 14) while语句 15) break与continue关键字 16) while…else语句 12,if语句        Note: 在一个if语 ...

  6. hdu 1166敌兵布阵(线段树入门题)

    >>点击进入原题测试<< 思路:这两天在学线段树,这个题直接手敲一下线段树就行了,都没有用上懒人标记.入门题 cin,cout会超时,记得加std::ios::sync_wit ...

  7. CodeForcesGym 100753B Bounty Hunter II

    Bounty Hunter II Time Limit: 5000ms Memory Limit: 262144KB This problem will be judged on CodeForces ...

  8. NYOJ 832 合并游戏

    合并游戏 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 大家都知道Yougth除了热爱编程之外,他还有一个爱好就是喜欢玩.某天在河边玩耍的时候,他发现了一种神奇的石 ...

  9. RMI分布式议程服务学习

    转自:http://6221123.blog.51cto.com/6211123/1112619 这里讲述的是基于JDK1.5的RMI程序搭建,更简单的说是一个 HelloWorld RMI. 1. ...

  10. 如何用js往html页面拼接一个div包括div的各种常用属性

    $("#div").append("<table><tr align='center'>" +"<td >&quo ...