目录
题目描述:
老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来才有学分。
每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为10,要求在 6 天内交,那么要想拿到这10学分,就必须在第6天结束前交。
每个作业都需要一天的时间完成。
例如,假设有 7 次作业的学分和完成时间如下:
作业号 | 期限 | 学分 |
---|---|---|
1 | 1 | 6 |
2 | 7 | |
3 | 3 | 2 |
4 | 1 | |
5 | 2 | 4 |
6 | 5 | |
7 | 6 | 1 |
最多可以获得 15 学分,其中一个完成作业的次序为 2,6,3,1,7,5,4注意可能还有其他方法。
你的任务就是找到一个完成作业的顺序获得最大学分。
输入格式
第一行一个整数 N,表示作业的数量;
接下来 N 行,每行包括两个整数,第一个整数表示作业的完成期限,第二个数表示该作业的学分。
输出格式
输出一个整数表示可以获得的最大学分。保证答案不超过 C/C++
的 int
范围。
样例
输入数据
7
1 6
1 7
3 2
3 1
2 4
2 5
6 1
输出数据
15
数据范围与提示
对于 20% 的数据,N≤10^3;
对于 40% 的数据,N≤10^4;
对于 60% 的数据,N≤10^5;
对于 100% 的数据,N≤106,作业的完成期限均小于 7*10^5。
程序步骤设计:
1、结构体加排序(学分从大到小,期限从小到大)
2、并查集(查找天数)
3、循环枚举(最好是当天作业当天完成)
代码+理解:
#include<bits/stdc++.h>
using namespace std;
const int N=1000001;
struct Node
{
int t,w;
}a[N]; //需要同时对学分和期限进行排序
bool cmp(Node a,Node b) // 结构体排序规则
{
if(a.w==b.w) return a.t<b.t; // 如果学分相同,优先做期限短的,确保完成作业,不同则直接按学分大小排
return a.w>b.w;
}
bool b[N];// 记录有没有时间做当前作业
int l[N];// 并查集
int find(int x)// 查找上级
{
if(l[x]!=x) l[x]=find(l[x]);
return l[x];
}
int main()
{
int n,ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d %d",&a[i].t,&a[i].w);// 输入
sort(a+1,a+n+1,cmp);// 排序
for(int i=1;i<=n;i++) l[i]=i;// 赋初值
for(int i=1;i<=n;i++)// 循环作业
{
for(int j=a[i].t;j>=1;j=l[j])// 循环做作业的时间
if(b[j]==0)// 当天有空
{
b[j]=true,l[j]--,ans+=a[i].w;// 记录并加入答案
break;
}
l[a[i].t]=find(a[i].t);
}
printf("%d",ans);//输出
return 0;
}