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+;
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 购物 —— 贪心的更多相关文章
- JZOJ 5461. 【NOIP2017提高A组冲刺11.8】购物
5461. [NOIP2017提高A组冲刺11.8]购物 (File IO): input:shopping.in output:shopping.out Time Limits: 1000 ms ...
- JZOJ 5459 购物
Description X 城的商场中,有着琳琅满目的各种商品.一日,小X 带着小Y 前来购物,小Y 一共看中了n件商品,每一件商品价格为Pi.小X 现在手中共有m个单位的现金,以及k 张优惠券.小X ...
- JZOJ.1150【贪心算法】IQ
欢迎转载,请附上原链接https://www.cnblogs.com/Code-Garden/p/11276741.html(也没人会看) 一道对我来说较难的贪心题 题目描述 根据世界某权威学会的一项 ...
- JZOJ.1153【贪心算法】硬币交换
好难啊!!! 可聪明的我还是解出来了!(逃 题目描述 小z最近迷上了一款游戏――To Be A Farmer,他在游戏中控制的人物是一个叫FZ的Farmer.FZ身上有G1个金币.S1个银币和B1个铜 ...
- JZOJ 1154. 【GDOI2003】购物
1154. [GDOI2003]购物 (Standard IO) Time Limits: 1000 ms Memory Limits: 65536 KB Description GDOI商场推出优惠 ...
- [jzoj 4879] [NOIP2016提高A组集训第11场11.9] 少女觉 解题报告 (贪心)
题目链接: http://172.16.0.132/senior/#main/show/4879 题目: 在幽暗的地灵殿中,居住着一位少女,名为古明地觉.据说,从来没有人敢踏入过那座地灵殿,因为人们恐 ...
- JZOJ 4611. 【NOI2016模拟7.11】接水问题 (贪心+A*+可持久化线段树)
Description: https://gmoj.net/senior/#main/show/4611 题解: 先把A从大到小排序,最小的由排序不等式显然. 考虑类似第k短路的A*的做法. 定义状态 ...
- [jzoj]1729.blockenemy
Link https://jzoj.net/senior/#main/show/1729 Description 你在玩电子游戏的时候遇到了麻烦...... 你玩的游戏是在一个虚拟的城市里进行,这个城 ...
- 洛谷P1658 购物
题目戳 题目描述 你就要去购物了,现在你手上有N种不同面值的硬币,每种硬币有无限多个.为了方便购物,你希望带尽量少的硬币,但要能组合出1到X之间的任意值. 输入输出格式 输入格式: 第一行两个数X.N ...
随机推荐
- 生成count个[0-n)不重复的随机数
代码来自:https://www.cnblogs.com/ningvsban/p/3590722.html,感觉实现的方式不错(做了一点小小修改) public static ArrayList ge ...
- Python字符的转义
参考原文 廖雪峰Python教程 字符的转义 字符串是以单引号' 或双引号" 括起来的任意文本,比如'abc',"xyz".''或""本身只是一种表示 ...
- Java对象序列化为什么要使用SerialversionUID
1.首先谈谈为什么要序列化对象 把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通 ...
- 腾讯云:基于 Ubuntu 搭建 VNC 远程桌面服务
基于 Ubuntu 搭建 VNC 远程桌面服务 前言 任务时间:5min ~ 10min 必要知识 本教程假设您已学习以下 Ubuntu 基本操作: 连接 SSH 执行命令 编辑文件 如果还没有掌握 ...
- MySQL Connector/Python 接口 (一)
这里仅介绍 MySQL 官方开发的 Python 接口,参见这里: https://dev.mysql.com/doc/connector-python/en/ Chapter 1 Introduct ...
- UVALive 6510 Stickers
Stickers Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Original ...
- UVA 10692 Huge Mod
Problem X Huge Mod Input: standard input Output: standard output Time Limit: 1 second The operator f ...
- scrapy——中间件UserAgent代理
pip install fake-useragent 使用说明:from fake_useragent import UserAgent# 实例化一个UserAgent对象ua = UserAgent ...
- [NOIP2004]FBI树
题目描述 我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串. FBI树是一种二叉树,它的结点类型也包括F结点,B结点和I结点三 ...
- cogs——1298. 通讯问题
1298. 通讯问题 ★★ 输入文件:jdltt.in 输出文件:jdltt.out 简单对比时间限制:1 s 内存限制:128 MB [题目描述] 一个篮球队有n个篮球队员,每个队员 ...