超市里有N个商品. 第i个商品必须在保质期(第di天)之前卖掉, 若卖掉可让超市获得pi的利润.
每天只能卖一个商品.
现在你要让超市获得最大的利润.
Input
多组数据.
每组数据第一行为一个整数N (0 <= N <= 10000), 即超市的商品数目
之后N行各有两个整数, 第i行为 pi, di (1 <= pi, di <= 10000)
Output
对于每一组数据, 输出当前条件下超市的最大利润
Sample Input
4
50 2
10 1
20 2
30 1
7
20 1
2 1
10 3
100 2
8 2
5 20
50 10
Sample Output
80
185
这道题目一开始想用贪心来做,也可以使用并查集来做,使用并查集只是在查找速度上面更快一点,使用普通的贪心也是可以AC的。这道题目的意思就是给出一些商品和他们的保质期,在保质期内将商品卖出的受益最大,但是每天只能卖出一件,所以我们得合理的卖出商品,将最贵的先卖出去,然后看看保质期,谁还能卖出去,再去卖谁,就这样,一直卖到最后就是最大值。
普通贪心,将商品价钱从大到小排序,然后用标记数组来标记商品(标记数组下标是第几天,就是判断这个商品在这天卖没有卖出去,因为一天只能卖出一个商品,我们就得先卖出去那个最贵的商品,然后再看其他的商品),如果当前商品没有被标记,我们就直接卖掉就可以了,如果被标记了,我们再从保质期那天往前推,知道哪一天没有出售商品,我们就那一天出售它就行了,比如说100 5 ,第五天已经被其他商品占住了,我们就从 4 3 2 1 天里面找一天,看看 哪一天没有出售商品,然后在那一天出售商品。代码:
#include<iostream>
#include<cstdio>
#include<map>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=10005;
typedef struct
{
int val;
int time;
}point;
point a[maxn];
int vis[maxn];
bool cmp(point a,point b)
{
return a.val>b.val;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
scanf("%d%d",&a[i].val,&a[i].time);
}
sort(a,a+n,cmp);
int sum=0;
for(int i=0;i<n;i++)
{
if(!vis[a[i].time])
{
sum+=a[i].val;
vis[a[i].time]=1;
}
else
{
for(int j=a[i].time-1;j>=1;j--)
{
if(!vis[j])
{
vis[j]=1;
sum+=a[i].val;
break;
}
}
}
}
printf("%d\n",sum);
}
return 0;
}
还有一个 并查集的写法:这个写法就有有点难想了,但是思想还是那个思想,我说说一下这个代码是怎么写的,是怎么来想的,首先也是需要一个标记数组(下标也是第几天被占,我们一开始就全部标记为-1)。
现在先说一下这个find 函数,就是下面这个函数,我们一开始将标记数组都设置为-1(一开始都没有被占),然后我们现在就要找一个没有被占的时间,如果pr[x]==-1,我们就选择这个时间了,在这里,我们知道保质期没有0天的,所以我们设置一个参照点就是pre[0]=-1 这个点,(为什么要设置这一个点呢),比如我们一个时间点,被占了的话,那么我们是不是要从 这个天数逐渐减到1天去寻找那个没有被占的时间点,在这个find 函数里面,就是这个原理。来我举一个例子说说这个原理吧 :
for(int i=0;i<n;i++)
{
int t=find(a[i].time);
if(t>0)
{
sum+=a[i].val;
pre[t]=t-1;
}
}
int find(int x)
{
return pre[x]==-1?x:pre[x]=find(pre[x]);
}
这四个数据
50 2
30 1
20 2
10 1
一开始
pre[0]=-1 pre[1]=-1 pre[2]=-1 pre[3]=-1 pre[4]=-1
1.先看 50 2这组数据
判断 pre[2]==-1? 等于-1,我们就把 pre[2]=2-1=1 卖
2.再看 30 1这组数据
判断 pre[1]==-1? 等于-1,我们就把 pre[1]=1-1=0 卖
3.再看 20 2这组数据,pre[2]==1 ->find,->pre[1]=0 ->find->pre[0]==-1 ,返回 0天,因为没有0天 ,不能卖
4.再看 10 1 这组数据 pre[1]=0 ->find-> pre[0]==-1 ,返回0天 ,因为没有 0天,不能卖
所以就是上面这个原理,find函数 就相当于一个往上找的函数 ,直到找到那个没有被占的时间点,然后将他的pre[ ]数组标记为上一天,使得能在其他的时间点卖掉。
然后就是我们卖掉一个商品,我们将vis[ 它的保质期 ]赋值为保质期-1,
#include<iostream>
#include<cstdio>
#include<vector>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
typedef long long ll;
using namespace std;
const int maxn=10005;
typedef pair<int,int> p;
typedef struct
{
int val;
int time;
}point;
int pre[maxn];
point a[maxn];
int find(int x)
{
return pre[x]==-1?x:pre[x]=find(pre[x]);
}
bool cmp(point a,point b)
{
return a.val>b.val;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
memset(pre,-1,sizeof(pre));
for(int i=0;i<n;i++)
{
scanf("%d%d",&a[i].val,&a[i].time);
}
sort(a,a+n,cmp);
int sum=0;
for(int i=0;i<n;i++)
{
int t=find(a[i].time);
if(t>0)
{
sum+=a[i].val;
pre[t]=t-1;
}
}
printf("%d\n",sum);
}
return 0;
}