poj1456-Supmarket

题目链接:http://poj.org/problem?id=1456

题目大意

给定N个商品,每个商品有利润Pi和过期时间Di,每天只能卖一个商品,过期商品不能再卖,如如何安排每天卖的商品,可以使收益最大。 

分析

在一定的时间内,卖的商品的利润尽可能大,肯定是最贵的先卖出,最贵的商品什么时候卖出?如果要使得利润最大化,我们可以在商品过期之间尽量晚卖出,这样就可以腾出时间卖其它较贵的商品。

本题其实是贪心算法中经典的加工生产调度问题(job sequencing with deadlines)

详细的过程可以查看视频:https://www.youtube.com/watch?v=zPtI8q9gvX8

N=7,Deadlines=4,假设所有作业都已经按收益从大小到排序。

Jobs

Job1

扫描二维码关注公众号,回复: 11653084 查看本文章

Job2

Job3

Job4

Job5

Job6

Job7

Rrofits

35

30

25

20

15

12

5

Deadlines

3

4

4

2

3

1

2

有4个时间段是可使用的。

1.安排Job1,根据贪心策略,放到时间段3

    Job1  

2.安排Job2,放到时间段4

    Job1 Job2

3.安排Job3,Job3的deadline为4,时间段3和时间段4已经被利润更高的Job1和Job2占领,因此Job3只能放到时间段2

  Job3 Job1 Job2

4.安排Job4,放到时间段1

Job4 Job3 Job1 Job2

思考:当安排某个Job时,如何找到最近的一个未使用的时间段?

可以使用并查集来维护时间段的占用情况

如安排完Job1时,将3和2合并为一个集合,安排Job2时,再将4和3合并为一个集合,这样在安排Job3时,可以直接定位到位置2是当前可用的。需要注意的是使用并查集维护可用的时间段时,要把位置靠前的元素设置为根。

参考代码

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int MAXN=10003;

struct Node{
	int prof;//profit
	int dl;//deadline
};
bool cmp(Node a,Node b){
	return a.prof>b.prof;
}

Node a[MAXN];
int n;
int f[MAXN];

int findRoot(int x){
	if(x==f[x]) return x;
	else return f[x]=findRoot(f[x]);
}
void mergeEle(int x,int y){
	f[y]=x; //不可写成f[x]=y,需要设置靠前的元素为根
}
int main(){
	
	int ans=0;	
	while(scanf("%d",&n)!=EOF){
	ans=0;
	for(int i=1;i<MAXN;i++) f[i]=i;
	for(int i=1;i<=n;i++)
		scanf("%d%d",&a[i].prof,&a[i].dl);
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++){
		int index=findRoot(a[i].dl);
		if(index>=1) {
			ans+=a[i].prof;
			mergeEle(index-1,index);
		}
	}
	printf("%d\n",ans);
}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/Zerotogether/article/details/94377544