博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【贪心+并查集/优先队列】POJ1456 Supermarket
阅读量:5254 次
发布时间:2019-06-14

本文共 5378 字,大约阅读时间需要 17 分钟。

Supermarket
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 17974   Accepted: 8071

Description

A supermarket has a set Prod of products on sale. It earns a profit px for each product x∈Prod sold by a deadline dx that is measured as an integral number of time units starting from the moment the sale begins. Each product takes precisely one unit of time for being sold. A selling schedule is an ordered subset of products Sell ≤ Prod such that the selling of each product x∈Sell, according to the ordering of Sell, completes before the deadline dx or just when dx expires. The profit of the selling schedule is Profit(Sell)=Σ
x∈Sellpx. An optimal selling schedule is a schedule with a maximum profit. 
For example, consider the products Prod={a,b,c,d} with (pa,da)=(50,2), (pb,db)=(10,1), (pc,dc)=(20,2), and (pd,dd)=(30,1). The possible selling schedules are listed in table 1. For instance, the schedule Sell={d,a} shows that the selling of product d starts at time 0 and ends at time 1, while the selling of product a starts at time 1 and ends at time 2. Each of these products is sold by its deadline. Sell is the optimal schedule and its profit is 80. 
Write a program that reads sets of products from an input text file and computes the profit of an optimal selling schedule for each set of products. 

Input

A set of products starts with an integer 0 <= n <= 10000, which is the number of products in the set, and continues with n pairs pi di of integers, 1 <= pi <= 10000 and 1 <= di <= 10000, that designate the profit and the selling deadline of the i-th product. White spaces can occur freely in input. Input data terminate with an end of file and are guaranteed correct.

Output

For each set of products, the program prints on the standard output the profit of an optimal selling schedule for the set. Each result is printed from the beginning of a separate line.

Sample Input

4  50 2  10 1   20 2   30 17  20 1   2 1   10 3  100 2   8 2   5 20  50 10

Sample Output

80185

Hint

The sample input contains two product sets. The first set encodes the products from table 1. The second set is for 7 products. The profit of an optimal schedule for these products is 185.
 
题目链接:
参考题解:  
 
题目大意是超市卖n个商品,每个商品都有自己的截止时间dx和利润px,在截止时间之前都可以卖掉它,且每个单位时间只能卖一件。问最大获利。
 
【思路一:贪心】
一开始的想法是用贪心,把每个商品利润从高到低排序,保证利润高的能“先”卖出去(优先级高)。每个商品在截止时间那天卖出,如果有重复的就把时间往前推,直到找到第一个空出的时间卖掉。
写了个简单贪心,没有优化,POJ上耗时141MS,代码如下:
1 #include 
2 #include
3 #include
4 #include
5 #include
6 using namespace std; 7 8 struct product{ 9 int px; //利润和截止时间10 int dx;11 }x[10005];12 13 bool cmp(product a,product b){ //根据利润从大到小排序14 return a.px > b.px;15 }16 17 int main(){18 int n;19 int table[10005];20 while(cin>>n){21 int sum = 0;22 memset(x,0,sizeof(product)*10005);23 memset(table,0,sizeof(table));24 for(int i = 0;i
=1) tmp--; //如果该时间单位已满,则往找前第一个空的时间单位占位35 if(tmp!=0){36 table[tmp] = 1;37 sum += x[i].px;38 }39 }40 }41 printf("%d\n", sum);42 }43 return 0;44 }

 

【思路二:贪心+优先队列】
代码提交之后总觉得还会有别的更好的的方法,搜了搜大佬们的博客,发现了另一种贪心思路。“ 每卖一个产品要占用一个时间单位,所以,我们可以一个单位一个单位时间地依次决定,每个时间要卖哪个产品,并且保证每个单位时间卖出的产品都是利润最大的,这样便能保证最终结果是最大的。如果枚举时间从小到大的话,那么比较麻烦,更好
的办法是从最后一个截至时间开始往前枚举, 这样的话,只要把截止时间大于等于这个时间段的产品都放入优先队列,其中利润最大的便是这时间所要的。 “
这个思路是用贪心+优先队列实现的,我也敲了一遍,POJ耗时63MS,代码如下:
1 #include 
2 #include
3 #include
4 #include
5 #include
6 using namespace std; 7 8 struct product{ 9 int px; //利润和截止时间10 int dx;11 }x[10005];12 13 bool cmp(product a,product b){ //根据截止时间从大到小排序14 return a.dx > b.dx;15 }16 17 priority_queue
,less
> q; //从大到小排列18 19 int main(){20 int n;21 while(~scanf("%d",&n)){22 int sum = 0;23 for(int i = 0;i
=1;--i){30 while(pos

 

【思路三:贪心+并查集优化】

看到的第三种思路实际上是第一种思路的优化,用到了并查集。一个商品可以在它的截止时间之前卖出,且一个时间只能卖一个商品。所以从后往前,找到商品的截止时间之前的第一个空位,并在当天卖出,然后标记那天已被占用。当时间被占用时,把当天时间标记为它的前一个时间,表示下次搜索空位时直接从前一个位置搜索。用并查集优化,在往前搜索空位的过程中,途中经过的所有位置都直接标记到最后搜到的那个空位上去,这样再次搜索这些点前面的空位时,可直接从上一次搜到的空位开始往前搜。这次的代码POJ耗时47MS,代码如下:

1 #include 
2 #include
3 #include
4 #include
5 using namespace std; 6 7 const int N = 10005; 8 struct product{ 9 int px,dx;10 }x[N];11 bool cmp(product a,product b){12 return a.px > b.px; //根据利润从大到小排序13 }14 15 int f[N];16 int find(int x){ //找截止时间前空着的时间,返回从后往前找到的第一个17 if(f[x] == -1) return x; //如果当前时间未被占用,直接返回18 return f[x] = find(f[x]); //当前时间已被占用,从它标记处从后往前开始搜,并把搜到的第一个空位直接标记给它和中间经过的点19 }20 21 int main()22 {23 int n;24 while(cin>>n){25 memset(f,-1,sizeof (f)); //全部初始化为-1,表示空位(此处不可初始化为0,否则在find步骤会产生影响)26 for(int i = 0;i < n; i++)27 scanf("%d%d",&x[i].px,&x[i].dx);28 sort(x,x+n,cmp);29 int sum = 0;30 for(int i = 0; i < n;i++){31 int t = find(x[i].dx); //找到当前物品截止时间前空着的时间32 if(t>0){ //找到的空着的时间单位不为033 sum += x[i].px;34 f[t] = t-1; //表示当前时间已被占用,下次搜索直接搜前一个时间是否为空35 }36 }37 printf("%d\n",sum);38 }39 40 return 0;41 }

 

总结:并查集确实是个好东西,在学会的同时也不能死套模板,能把它用到实处才是真正的理解。希望下次可以自己写出更好的优化!

 

转载于:https://www.cnblogs.com/Aikoin/p/10160602.html

你可能感兴趣的文章
ProxySQL Scheduler
查看>>
源代码的下载和编译读后感
查看>>
Kafka学习笔记
查看>>
Octotree Chrome安装与使用方法
查看>>
用CALayer实现下载进度条控件
查看>>
Windows 环境下基于 Redis 的 Celery 任务调度模块的实现
查看>>
趣谈Java变量的可见性问题
查看>>
C# 强制关闭当前程序进程(完全Kill掉不留痕迹)
查看>>
ssm框架之将数据库的数据导入导出为excel文件
查看>>
语音识别中的MFCC的提取原理和MATLAB实现
查看>>
验证组件FluentValidation的使用示例
查看>>
0320-学习进度条
查看>>
解决windows系统的oracle数据库不能启动ora-00119和ora-00130的问题
查看>>
ip相关问题解答
查看>>
MetaWeblog API Test
查看>>
反弹SHELL
查看>>
关闭Chrome浏览器的自动更新和升级提示
查看>>
移动、尺寸改变
查看>>
poj2255Tree Recovery【二叉树重构】
查看>>
tcpcopy 流量复制工具
查看>>