题目: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. 小程序wx:key = “{{*this}}”报错

    解决方案:改为 wx:key = "*this"

  2. idea安装及使用

    使用:https://blog.csdn.net/qq_42303709/article/details/81983208 安装教程:https://blog.csdn.net/yl171272518 ...

  3. 什么是 C 和 C ++ 标准库?

    简要介绍编写C/C ++应用程序的领域,标准库的作用以及它是如何在各种操作系统中实现的. 我已经接触C++一段时间了,一开始就让我感到疑惑的是其内部结构:我所使用的内核函数和类从何而来? 谁发明了它们 ...

  4. JDBC插入数据时中文变为问号的解决方法

    JDBC插入数据时中文变为问号的解决方法 制作人:全心全意 出现中文变问号的代码: String url = "jdbc:mysql://localhost:3306/test"; ...

  5. ubuntu root用户登陆

    sudo vi /etc/lightdm/lightdm.conf   (如果没有该文件则创建,内容如下) [SeatDefaults] user-session=ubuntu greeter-ses ...

  6. 百练4103:踩方格(DFS)

    描述 有一个方格矩阵,矩阵边界在无穷远处.我们做如下假设:a.    每走一步时,只能从当前方格移动一格,走到某个相邻的方格上:b.    走过的格子立即塌陷无法再走第二次:c.    只能向北.东. ...

  7. 在eclipse中如何在大量项目中查找指定文件

    在eclipse中如果希望在大量的项目中寻找指定的文件可不是一件轻松的事,还好eclipse提供了强大的搜索功能. 我们可以通过通配符或正则表达式来设定查寻条件,下面是操作示例: ctrl+h 打开搜 ...

  8. 【Codeforces 1038D】Slime

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 相当于让你确定每个数字前面的系数是-1还是+1 有个结论是这样每次和相邻的减的话, 任何出除了全"-1"和全"+ ...

  9. 最接近的点配对(分治问题理解) && HDU 1007代码

    题目大意: 给定一堆点集,在这一堆点集中找到一组点集它们之间的距离达到最短 对于HDU1007因为求圆的半径,所以距离还要除以2 普通情况下,可以将nge点,将任意两个点之间的距离都算一遍,在循环过程 ...

  10. windows安装Reids

    1.下载windows版本,64位,3.0版本就可以 官网下载地址:http://redis.io/download github下载地址:https://github.com/MSOpenTech/ ...