家庭作业(贪心+并查集)
老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为 10,要求在 6 天内交,那么要想拿到这 10 学分,就必须在第 6 天结束前交。
每个作业的完成时间都是只有一天。例如,假设有 7 次作业的学分和完成时间如下:
最多可以获得 15 学分,其中一个完成作业的次序为 2,6,3,1,7,5,4注意可能还有其他方法。
你的任务就是找到一个完成作业的顺序获得最大学分。
【输入格式】
第一行一个整数 N,表示作业的数量;
接下来 N 行,每行包括两个整数,第一个整数表示作业的完成期限,第二个数表示该作业的学分。
【输出格式】
输出一个整数表示可以获得的最大学分。保证答案不超过 C/C++ 的 int 范围。
【样例输入】
7
1 6
1 7
3 2
3 1
【样例输出】
15
思路: 数据太大,暴力就不好使了,这里引入并查集来解决问题,f[i]=x,表示第i天前面最大的能用的一天为第x天,x这一天被用之后,就要更新f[i],那就找第x-1天前最大能用的为第几天放入f[i]中
AC代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int book[1100000],f[1100000];
struct pp
{
int a,b;
}p[1100000];
bool cmp(pp x,pp y)
{
return x.b>y.b;
}
void init()
{
for(int i=0;i<=1100000;i++)
f[i]=i;//初始第i天前最大能用的为本身
}
int find(int x)//并查集
{
if(f[x]==x)
return x;
return f[x]=find(f[x]);
}
int main()
{
int n,i,j,k;
init();
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d%d",&p[i].a,&p[i].b);
sort(p,p+n,cmp);
int sum=0;
for(i=0;i<n;i++)
{
int xx=find(p[i].a);//p[i].a前能用的最大为第xx天
if(xx)//xx存在,即p[i].a前还有天可用
{
sum+=p[i].b;//加学分
int yy=find(xx-1);//找xx前一天能用的为第几天
f[xx]=yy;//更新
}
}
printf("%d\n",sum);
return 0;
}