题目链接:POJ-1456

题目大意

有n件商品,每件商品的利润为,销售日期的截止时间为(即只能在时间前销售该物品)。一天只能销售一件物品。问这n件商品的最大利润为多少

方案一

分析

有两种贪心策略,现介绍第一种:

将商品按利润从大到小排序,优先考虑利润大的商品。那么该商品可以在其截止日期前的任一时间销售,那么肯定越晚销售越好,因为越晚销售对其他商品的影响越小,越有可能卖出更多的截止时间在它之前的商品。

核心代码:

p数组储存商品,sold数组记录某一天是否已经被占用了。

假设一件商品的截至时间为d,因为我们希望它能尽可能晚地卖出去,所以从第d天开始不断往前找空闲的时间点,找到之后将该时间点标记为被占用

 for(int i=1;i<=N;i++)for(int j=p[i].deadline;j>=1;j--){if(!sold[j]){sold[j]=1;ans+=p[i].profit;break;}}

复杂度:O()

但是这道题数据比较弱仍然可以过

优化

朴素的做法在枚举每件商品时都会从其截至日期不断往前找没被占用的时间点

我们可以用一个pre数组记录该时间点前最近的一个空闲时间点

比如已知第4-17天都被占用了,而一件商品的截至时间是第16天

那么pre[16]=3,即指向下一个空闲的时间点,我们就将该商品在第3天卖掉即可,而不用从16再枚举到3了。

如果pre[x]=0,则表明1-x天都被占用了,说明该商品不可能卖出去了

这么做就可以避免暴力找解

具体实现:

首先初始化pre数组为-1,表示都空闲

当第x天被占用,我们将pre[x]的值修改为x-1,表示下一个可能空闲的时间点是第x-1天

之所以是可能空闲的时间点,因为可能第x-1天也被占用了

可以联想树结构方便理解:

每一个结点的父结点都是下个可能空闲时间的结点,而根节点就是空闲的时间点

我们用一个_find函数来从结点遍历到根节点就能找到空闲的时间点了

而其实我们希望pre数组能直接指向根节点

因此在查找函数中路径压缩即可

其实这就是一个并查集了,要不断查询某一个时间点的前一个可能空闲时间点,还需要合并操作(如果某时间点x被占用,则合并到时间点x-1的集合中去,成为x-1结点的子树)

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;typedef struct{int profit;int deadline;
}product;product p[10005];
int pre[100005];bool cmp(product a,product b){if(a.profit!=b.profit)return a.profit>b.profit;return a.deadline>b.deadline;
}int _find(int x){return pre[x]==-1?x:pre[x]=_find(pre[x]);
}int main()
{int N;while(~scanf("%d",&N)){memset(pre,-1,sizeof(pre));for(int i=1;i<=N;i++)scanf("%d %d",&p[i].profit,&p[i].deadline);sort(p+1,p+N+1,cmp);int ans=0;for(int i=1;i<=N;i++){int time=_find(p[i].deadline);if(time>0){//如果为0则说明这个商品已经没有位置可以放了ans+=p[i].profit;pre[time]=time-1;}}printf("%d\n",ans);}return 0;
}

方案二

分析

还有另外一种贪心策略,按商品的截止时间从小到大排,优先考虑截止时间前的商品。当发现当前商品截止时间为d,利润为p且无法售卖时(即前d天已经安排了d种商品售卖),寻找这d种商品利润最小的,如果该利润小于p,则可以用当前商品去替换掉利润最小的商品,同样是O()的做法,但是可以利用小根堆进行优化。

代码

#include <cstdio>
#include <string.h>
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;const int maxn=1e4+5;
typedef struct{int profit;int deadline;
}product;bool operator < (product a,product b){return a.deadline<b.deadline;
}product goods[maxn];int heap[maxn]; //小根堆
int cnt=1;void up(int p){//向上调整while(p>1){if(heap[p]<heap[p/2]){swap(heap[p],heap[p/2]);p/=2;}else break;}
}void down(int p){ //向下调整int s=p*2;while(s<cnt){if(s<cnt-1&&heap[s]>heap[s+1]) s++;if(heap[s]<heap[p]){swap(heap[s],heap[p]);p=s;s=p*2;}else break;}
}void Insert(int value){heap[cnt]=value;up(cnt);cnt++;
}void Extract(){heap[1]=heap[--cnt];down(1);
}void Remove(int k){heap[k]=heap[--cnt];up(k); down(k);
}void init(){memset(heap,0,sizeof(heap));cnt=1;
}int main()
{int N;while(~scanf("%d",&N)){init();for(int i=1;i<=N;i++)scanf("%d %d",&goods[i].profit,&goods[i].deadline);sort(goods+1,goods+N+1);int num=0;for(int i=1;i<=N;i++){if(goods[i].deadline>num){Insert(goods[i].profit);num++;}else{if(goods[i].profit>heap[1]){Extract();Insert(goods[i].profit);}}}int ans=0;for(int i=1;i<=num;i++)ans+=heap[i];printf("%d\n",ans);}return 0;
}

【贪心】 POJ 1456 Supermarket 详解 (并查集/二叉堆优化)相关推荐

  1. 图论-欧拉图-欧拉回路-Euler-Fluery-Hierholzer-逐步插入回路法-DFS详解-并查集

    欧拉图性质: 1.无向连通图G是欧拉图,当且仅当G不含奇数度结点(G的所有结点度数为偶数): 2.无向连通图G含有欧拉通路,当且仅当G有零个或两个奇数度的结点: 3.有向连通图D是欧拉图,当且仅当该图 ...

  2. 拓扑排序 详解 + 并查集 详解 + 最小生成树详解

    若您发现本文有什么错误,请联系我,我会及时改正的,谢谢您的合作! 本文为原创文章,转载请注明出处 本文链接   : http://www.cnblogs.com/Yan-C/p/3943940.htm ...

  3. 7-3 最小生成树-kruskal (10 分)(思路+详解+并查集详解+段错误超时解决)宝 Come

    一:前言 本题需要用到并查集的知识,建议先学完并查集后再看看本题 二:题目 题目给出一个无向连通图,要求求出其最小生成树的权值. 温馨提示:本题请使用kruskal最小生成树算法. 输入格式: 第一行 ...

  4. 7-25 朋友圈 (25 分)(详解+并查集的了解和应用)

    一:题目 某学校有N个学生,形成M个俱乐部.每个俱乐部里的学生有着一定相似的兴趣爱好,形成一个朋友圈.一个学生可以同时属于若干个不同的俱乐部.根据"我的朋友的朋友也是我的朋友"这个 ...

  5. 二叉堆详解实现优先级队列

    二叉堆详解实现优先级队列 文章目录 二叉堆详解实现优先级队列 一.二叉堆概览 二.优先级队列概览 三.实现 swim 和 sink 四.实现 delMax 和 insert 五.最后总结 二叉堆(Bi ...

  6. 支付接口教程,详解支付宝接口(二)

    支付宝的接口向来集成过程都让人觉得比较舒服,只有APP支付相对复杂,但也只是配置上复杂一些,只要清楚原理相信也不是什么难事.下面是以前介绍双钥加密原理的传送门: 支付接口教程特别篇,公钥与私钥,双钥加 ...

  7. PHP支付接口教程,详解微信支付(二)

    PC扫码支付 扫码支付首先是要分清楚两种模式: [模式一]:商户后台系统根据微信支付规则链接生成二维码,链接中带固定参数productid(可定义为产品标识或订单号).[模式二]:商户后台系统调用微信 ...

  8. 2017百度之星程序设计大赛 - 资格赛【1001 Floyd求最小环 1002 歪解(并查集),1003 完全背包 1004 01背包 1005 打表找规律+卡特兰数】...

    度度熊保护村庄 Accepts: 13 Submissions: 488 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/3276 ...

  9. 高位在前低位在后是啥意思_详解MACD指标的死叉卖点:低位死叉+高位死叉+零轴附近死叉...

    MACD最经典最简单的的用法就是金叉死叉了,但是对于这样简单的用法,想必还是有很多的股民不知道如何运用,所以今天越声攻略就给大家详细的讲解下详解MACD指标的死叉卖点:低位死叉+高位死叉+零轴附近死叉 ...

最新文章

  1. Zookeeper服务器集群的搭建与操作
  2. java bytearrayoutputstream 文件_Java ByteArrayInputStream和ByteArrayOutputStream示例
  3. Mybatis源码之缓存模块分析
  4. call,apply,bind的区别
  5. NGINX Plus集成fail2ban进行动态IP黑名单配置
  6. 容器编排技术 -- Kubernetes kubectl create poddisruptionbudget 命令详解
  7. [转载]Dynamic Database Switching in Rails - How to do it
  8. Linux命令备忘实例——排序和基本统计命令
  9. 开源C++项目Google JavaScript引擎V8挑战实录,带你进入V8之旅
  10. LVS学习系列(1)--入门
  11. 用单片机c语言输入8位输出,单片机C语言教程(二)
  12. 有趣好玩的python编程网站
  13. linux中iso文件怎么安装,linux系统安装iso文件方法
  14. 空间数据库管理方案及数据文件组织方式
  15. 方波的产生——555 产生方波
  16. 探寻Linux 中国之路
  17. python验证身份证最后一位数字代表什么_身份证号最后一位是“X”,代表什么意思?...
  18. OKR:打破组织中的沟通壁垒
  19. 【谈谈】动态规划——求最长公共子序列
  20. Pytorch squeeze()的简单用法

热门文章

  1. h5调用本地摄像头和麦克风一
  2. matlab画平面心形线,matlab三维心形线画法
  3. qduoj讨论版docker开发记录
  4. 小学计算机课认识键盘,小学信息技术认识键盘教学设计微课视频教学反思教材分析学情分析教学课程设计......
  5. 解决:启动Mybatis自动生成代码插件出现低级异常
  6. 创维E900-S-非高安_HI3798MV100_免拆或拆机短接强刷-当贝桌面卡刷固件包
  7. 老龄化社会,“免验”的验证码更重要
  8. 易开发是一款帮助开发人员快速开发的工具,功能包括界面分析,页面信息,加固脱壳,支持 Android9.0
  9. 2022年最新Java学习路线图
  10. 【一生一芯学习计划】如何使用GDB进行调试