问题描述
有n个任务,第个任务有自己的截止时间 和惩罚 。完成一个任务需要一个单位时间。我们期望任务在截止时间 前完成,这样我们不会受到惩罚,否则我们会受到 的惩罚。你的任务是找到一个调度方案,使得受到的惩罚总和尽量小。
输入格式
第一行一个正整数n(1≤n≤3*10^5)。
接下来n行,每行包含两个正整数di(1≤di≤n), wi(1≤wi≤1000),表示第i个任务的截止时间和惩罚。
输出格式
输出文件仅一行,包含一个正整数,即最小的惩罚总和。
样例输入
7
4 7
2 6
4 5
3 4
1 3
4 2
6 1
样例输出
5
样例解释
按顺序完成2, 4, 1, 3, 7号任务,放弃5, 6号任务,可以证明这样的调度方案受到的惩罚总和最小,为5。
来源 by Quack
题解:
要使受到的惩罚小,则可以考虑将前面惩罚小的任务替换为后面惩罚大且无法按时完成的任务。
将任务按惩罚从大到小排序。运用并查集压缩路径,直接找到当前任务的可行的截止时间。
#include<cstdio> #include<algorithm> using namespace std; const int N=1e5*3+10; /*fnd[i]:记录将i时间占用的任务的截止时间 nxtE[i]:下一个截止时间为i的任务的实际结束时间*/ int n, nxtE[N], fnd[N], sum; struct node{ int end, w; bool operator < ( const node &x ) const { if( w!=x.w ) return w>x.w; return end>x.end; } }tsk[N]; int main() { scanf( "%d", &n ); for( int i=1; i<=n; i++ ) scanf( "%d%d", &tsk[i].end, &tsk[i].w ), nxtE[i]=i; sort( tsk+1, tsk+n+1 ); for( int i=1; i<=n; i++ ) { int e=tsk[i].end; while( fnd[e] ) e=nxtE[ fnd[e] ]; if(e) nxtE[tsk[i].end]=e-1, fnd[e]=tsk[i].end; else sum+=tsk[i].w; } printf( "%d\n", sum ); return 0; }
[BZOJ3396]任务调度
最新推荐文章于 2021-05-23 21:28:51 发布