【C++】「一本通 1.1 练习 4」家庭作业

【来源】

一本通题库-1430
LibreOJ-10008
vjudge

【题目描述】

老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为 10 10 ,要求在 6 6 天内交,那么要想拿到这 10 10 学分,就必须在第 6 6 天结束前交。

每个作业的完成时间都是只有一天。例如,假设有 7 7 次作业的学分和完成时间如下:

作业号 期限 学分
1 1 6
2 7
3 3 2
4 1
5 2 4
6 5
7 6 1

最多可以获得 15 15 学分,其中一个完成作业的次序为 2 6 3 1 7 5 4 2,6,3,1,7,5,4 ,注意可能d还有其他方法。

你的任务就是找到一个完成作业的顺序获得最大学分。

【输入格式】

第一行一个整数 N N ,表示作业的数量。
接下来 N N 行,每行包括两个整数,第一个整数表示作业的完成期限,第二个数表示该作业的学分。

【输出格式】

输出一个整数表示可以获得的最大学分。保证答案不超过C/C++intPascallongint范围。

【输入样例】

7
1 6
1 7
3 2
3 1
2 4
2 5
6 1

【输出样例】

15

【数据范围】

对于 20% 的数据, N 1 0 3 N≤10^3
对于 40% 的数据, N 1 0 4 N≤10^4
对于 60% 的数据, N 1 0 5 N≤10^5
对于 100% 的数据, N 1 0 6 N≤10^6 ,作业的完成期限均小于 7 × 1 0 5 7×10^5

【解析1】

贪心。
先做学分大的作业。
将作业按学分从大到小排序,同分按时限降序。
假如学分最多的一个任务的完成期限是 k k ,我们应该放在小于等于 k k 的最靠后的时间段。
一旦出现一个不可能在规定期限内完成的时间,那就不做吧。

【代码1】

#pragma GCC optimize(3,"Ofast","inline")
#pragma G++ optimize(3,"Ofast","inline")

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>

#define RI                 register int
#define re(i,a,b)          for(RI i=a; i<=b; i++)
#define ms(i,a)            memset(a,i,sizeof(a))
#define MAX(a,b)           (((a)>(b)) ? (a):(b))
#define MIN(a,b)           (((a)<(b)) ? (a):(b))

using namespace std;

typedef long long LL;

int const N=1e6+5;

struct Node {
    int t,m;

    Node() {}

    Node(int t,int m) : t(t),m(m) {}

    bool operator < (const Node &rhs) const {
        if(t!=rhs.t) return t>rhs.t;
        return m<rhs.m;
    }
} a[N];

int n,ans=0;

priority_queue <int> q;

int main() {
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%d%d",&a[i].t,&a[i].m);
    sort(a+1,a+n+1);
    int j=1;
    for(int i=a[1].t; i>=1; i--) {
        while(j<=n && a[j].t==i) {
            q.push(a[j].m);
            j++;
        }
        if(q.empty()) continue;
        ans+=q.top();
        q.pop();
    }
    printf("%d\n",ans);
    return 0;
}

【解析2】

本题还可以用并查集。

按学分从大到小排序,那么我们会尽可能地让作业的完成时间延后,这样就能有更多空间给那些限制比较严格的作业。

f [ i ] f[i] 为点 i i 向左的最小空闲时间。
对于一个限制t的作业,我们将它放在 f [ t ] f[t] 上,同时使 f [ t ] = f [ t ] 1 f[t]=f[t]-1 (表示这个时间被占用了)。
就可以用并查集维护了。

时间复杂度 O ( N l o g N + T ) O(N log N+T) ,其中 T T 是最大期限

【代码2】

#pragma GCC optimize(3,"Ofast","inline")
#pragma G++ optimize(3,"Ofast","inline")

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

#define RI                 register int
#define re(i,a,b)          for(RI i=a; i<=b; i++)
#define ms(i,a)            memset(a,i,sizeof(a))
#define MAX(a,b)           (((a)>(b)) ? (a):(b))
#define MIN(a,b)           (((a)<(b)) ? (a):(b))

using namespace std;

typedef long long LL;

int const N=1e6+5;

struct Node {
    int t,m;

    bool operator < (const Node &rhs) const {
        return m>rhs.m;
    }
} a[N];

int n,ans=0;
int fa[N];

inline int getfa(int x) {
    if(x!=fa[x]) fa[x]=getfa(fa[x]);
    return fa[x];
}

int main() {
    scanf("%d",&n);
    for(int i=1; i<=n; i++) 
        scanf("%d%d",&a[i].t,&a[i].m);
    sort(a+1,a+n+1);
    for(int i=1; i<=n; i++) fa[i]=i;
    for(int i=1; i<=n; i++) {
        int x=getfa(a[i].t);
        if(x) ans+=a[i].m,fa[x]=getfa(x-1);
    }
    printf("%d\n",ans);
    return 0;
}
发布了110 篇原创文章 · 获赞 160 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Ljnoit/article/details/105480837
今日推荐