题目链接:
http://poj.org/problem?id=1456
题意分析:
超市里有n件商品,每件商品有对应的利润p和销售的最后期限d,销售一件商品需要花费一个单位时间,给出商品集,问销售这些商品最大能获得多少利润?
解题思路:
因为在第n天出售商品不会影响前面n-1天的出售,可以想到每次出售商品都应在最接近最后期限的时间出售。以此可以想到贪心+暴力的思路,每次取出利润最大的商品,判断能否在最后期限之前出售,若能,将它在最接近最后期限的时间出售,并做标记。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 10100;
struct product
{
int p;
int d;
bool operator < (product pp) const
{
return p>pp.p || (p==pp.p&&d>pp.d);
}
}p[MAXN];
bool used [MAXN];
int n;
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
scanf("%d%d",&p[i].p,&p[i].d);
sort(p+1,p+n+1);
int ans = 0;
memset(used,false,sizeof(used));
for(int i=1;i<=n;i++)
{
for(int j=p[i].d;j>=1;j--)
{
if(!used[j])
{
used[j]=true;
ans+=p[i].p;
break;
}
}
}
printf("%d\n",ans);
}
return 0;
}
思路一的算法每次在为商品找可以出售的时间点时浪费了时间,可以使用优先权队列进行优化。
我们只需找到从最大期限到第一天每天能出售的最大利润的商品。先对所有商品按期限从大到小排序,每次将同一期限的商品全部放入优先权队列中,然后从最大的期限往前一天一天推,每天从优先权队列中取出当天能出售的最大利润的商品。
思路二:贪心+优先权队列(63ms)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN = 10100;
struct product
{
int p;
int d;
bool operator < (product pp) const
{
return d>pp.d || (d==pp.d&&p>pp.p);
}
}p[MAXN];
struct pq_product
{
int p;
pq_product(int pp)
{
p=pp;
}
bool operator < (pq_product pp) const
{
return p<pp.p;
}
};
int n;
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
scanf("%d%d",&p[i].p,&p[i].d);
p[n+1].d=0;
sort(p+1,p+n+1);
int ans = 0;
priority_queue<pq_product> pq;
pq_product temp(0);
for(int i=1;i<=n;i++)
{
int nowd=p[i].d;
temp=pq_product(p[i].p);
pq.push(temp);
while(p[i+1].d==p[i].d)
{
temp=pq_product(p[++i].p);
pq.push(temp);
}
for(int j=nowd;j>p[i+1].d;j--)
{
if(!pq.empty())
{
temp=pq.top();
pq.pop();
ans+=temp.p;
}
}
}
printf("%d\n",ans);
}
return 0;
}
由于是在并查集专题做到的这道题目,但实在想不出并查集的解法,搜了网上并查集的题解后,才知道并查集在这里是作为工具,查找利润最大的商品可以出售的最晚时间。
可以这样理解,比如,一件期限为6的商品出售之后,下次再出现期限为6的商品时,实际上该商品与期限5的商品相同,因为只能在前5天出售。这样我们便可以利用并查集,出售一个商品后,将这个期限与这个期限的前一天合并(大期限的父亲结点是小期限),这样每次我们只需要找到一个期限的祖先结点,就能知道这个结点最晚可以出售的日期。
思路三:贪心+并查集(63ms)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 10100;
struct product
{
int p;
int d;
bool operator < (product pp) const
{
return p>pp.p;
}
}p[MAXN];
int F[MAXN];
int find(int x)
{
if(F[x]==x)return x;
return F[x]=find(F[x]);
}
int n;
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=10000;i++)
F[i]=i;
for(int i=1;i<=n;i++)
scanf("%d%d",&p[i].p,&p[i].d);
sort(p+1,p+n+1);
int ans = 0;
for(int i=1;i<=n;i++)
{
int fi=find(p[i].d);
if(fi)
{
ans+=p[i].p;
F[fi]=fi-1;
}
}
printf("%d\n",ans);
}
return 0;
}