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 ...
随机推荐
- CodeFrist基础
Code First(代码先行).它思想就是先定义模型中的类,再通过这些类生成数据库.这种开发模式适合于全新的项目,它使得我们可以以代码为核心进行设计而不是先构造数据库. EF中创建数据库的表必须要有 ...
- 模板—AC自动机
#include<iostream> #include<cstdio> #include<cstring> using namespace std; struct ...
- 洛谷——P2054 [AHOI2005]洗牌(扩展欧几里得,逆元)
P2054 [AHOI2005]洗牌 扩展欧拉定理求逆元 $1 2 3 4 5 6$$4 1 5 2 6 3$$2 4 6 1 3 5$$1 2 3 4 5 6$ 手推一下样例,你就会发现是有规律的: ...
- 1007 Maximum Subsequence Sum (PAT(Advance))
1007 Maximum Subsequence Sum (25 分) Given a sequence of K integers { N1, N2, ..., NK }. A ...
- PHP上传文件到七牛(Qiniu)
上传文件到七牛最简单的方式就是使用七牛官方最新的SDK 安装PHP SDK composer require qiniu/php-sdk 上传文件到七牛 use Qiniu\Auth; use Qin ...
- PAT 1122 Hamiltonian Cycle
The "Hamilton cycle problem" is to find a simple cycle that contains every vertex in a gra ...
- textarea 高度调整
textarea 高度调整 通过 rows 属性调整 高度
- BZOJ 2095 [POI2010]Bridges (最大流、欧拉回路)
洛谷上有这题,但是输出方案缺SPJ..(而且我也懒得输出方案了) 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2095 题解: 首先判 ...
- BZOJ(4) 1050: [HAOI2006]旅行comf
1050: [HAOI2006]旅行comf Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3984 Solved: 2236[Submit][St ...
- 24、Java并发性和多线程-信号量
以下内容转自http://ifeve.com/semaphore/: Semaphore(信号量) 是一个线程同步结构,用于在线程间传递信号,以避免出现信号丢失(译者注:下文会具体介绍),或者像锁一样 ...