原题有点抽象这里就直接放的中文题目,做题的时候我一开始就都错题了QAQ,我理解成了他的保质期是第D天,那他就只能在第D天被卖出,结果一直wa,找了个正确代码一堆拍才知道题读错了。。。。,真就是读题一小时,做题5分钟了,不废话了,开始分析。
题目告诉我们商品必须在保质期之前卖掉才可以获得利润,那我们可以采用贪心的思路根据物品的价值从大到小进行排序,并用一个数组对卖出物品的那一天进行标记,如果物品在它保质期的这一天可以卖出那就在这一天卖出,然后将这一天标记一下,否则就从保质期这一天开始往前找,一旦遇到可以没有被标记的天数就在这一天卖出并标记,注意这里要从后往前去找天数,也就是说尽量在靠后的那些天里卖出,以便于为后面的物品腾出时间,使时间得到最大化利用。
贪心代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N =1e4+10;
struct node {
int p,e;
}g[N];
bool vis[N];
int n;
bool cmp(struct node a,struct node b)
{
return a.p>b.p;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
scanf("%d%d",&g[i].p,&g[i].e);
sort(g+1,g+1+n,cmp);
long long ans=0;
memset(vis,false,sizeof vis);
for(int i=1;i<=n;i++)
{
if(!vis[g[i].e])
{
vis[g[i].e]=true;
ans+=g[i].p;
}
else
{
for(int j=g[i].e;j>=1;j--)
{
if(!vis[j])
{
vis[j]=true;
ans+=g[i].p;
break;
}
}
}
}
cout<<ans<<endl;
}
return 0;
}
做题的时候这个题的标签写的是并查集,但我想了半天也没看出来它跟并查集有啥关系,后来才明白并查集对于这个题来说其实是一种优化方法,在上面的贪心代码中我们看到如果在保质期这一天不能卖出的话,就要从后往前去枚举没有卖东西那一天,并查集其实就是用来优化这个循环的,首先对并查集的数组进行初始化,在选天的时候,一旦选择了当前的天,那就把当前天的父亲节点设为它的前一天,我们是用并查集路径压缩的特性将已经卖了东西的那些天进行了压缩,从而达到了优化的目的。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N =1e4+10;
struct node {
int p,e;
}g[N];
int f[N];
int n;
bool cmp(struct node a,struct node b)
{
return a.p>b.p;
}
int find(int x)
{
if(f[x]!=x)
f[x]=find(f[x]);
return f[x];
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
scanf("%d%d",&g[i].p,&g[i].e);
sort(g+1,g+1+n,cmp);
long long ans=0;
for(int i=1;i<=10000;i++)
f[i]=i;
for(int i=1;i<=n;i++)
{
int t=find(g[i].e);
if(t>0)
{
ans+=g[i].p;
f[t]=t-1;
}
}
cout<<ans<<endl;
}
return 0;
}
贪心代码是125ms,并查集是79ms,可以自行比较一下。