洛谷P2949 工作调度Work Scheduling题解

题目链接 :洛谷P2949

这道题目是一道很明显的贪心问题。可以发现每个工作代价(占用时间)均为一,而相应的价值(工作利润)不同。此时我们可以想到一个很显然的贪心策略,即

  1. 当工作的利润不同时,优先进行利润更大的工作
  2. 当工作的利润相同时,优先进行截止时间更晚的工作

根据以上贪心策略,对于工作,可以定义以下结构体

struct job{
    int end_time;//截止时间
    int value;//工作利润

    bool operator< (const job &J)const {//重载小于号
        if (value != J.value) return value > J.value;
        return end_time > J.end_time;
    }
}j[100005];


接下来考虑如何处理工作时间冲突的情况。由于排序后,数组前面的元素利润更大,显然,当为了使利润更高,应该将排序后数组中靠后的工作在截止时间之前进行。由于有$10^9$的单位时间,显然是开不下一个这么长的数组用来判断每个时间是否进行工作。考虑到工作数量N ≤ 106,我们使用一个set对每个时间是否进行工作进行存储。代码如下:

set<int> pr;//用于判断每个时间是否进行了工作
int main(){
    int n;
    cin>>n;
    for (int i = 1; i <= n; i++){
        cin>>j[i].end_time>>j[i].value;
    }
    sort(j + 1, j + n + 1);//对工作数组j进行排序
    long long ans = 0;//注意此处必须开long long,不然会爆掉
    for (int i = 1; i <= n; i++){
        while ( pr.count( j[i].end_time )  && j[i].end_time > 0) {
            j[i].end_time--;
        }//判断当前截止时间是否进行了工作,如果有工作在进行,那么将截止时间前移
        if ( j[i].end_time ){//如果当前工作在0时刻之前可以进行
            ans += j[i].value;//加上该工作的利润
            pr.insert( j[i].end_time );//记录当前时间
        }
    }
    cout<<ans<<endl;//输出
    return 0;
}


把这段代码提交评测,居然T了四个点?考虑对代码进行优化。不难发现,在将当前工作时间前移的while循环中浪费了大量的时间。当大量工作截止时间相同时,会进行大量重复计算。因此可以用一个类似于并查集的结构进行优化,记录下每个时间之前最晚可能没有进行工作的时间。使用map进行存储该结构与每个时间是否进行工作后,改写的while循环如下:

map<int, int> time_table;//用于存储每个时间之前最晚可能没有进行工作的时间

int now_time = j[i].end_time;
while ( pr[ j[i].end_time ] && j[i].end_time > 0) {
    if(time_table[ j[i].end_time ])//如果当前时间前有一段时间已经进行了工作 
        j[i].end_time = time_table[ j[i].end_time ]--;//向前跳跃一段时间
    else j[i].end_time--;//否则只向前进行一步
}
time_table[now_time] = j[i].end_time;//更新

这样,虽然循环中仍有部分重复计算,代码运行效率已经降低到可以接受的范围,完整的优化留作后续思考其实是我不想写QAQ。下面给出基于pbds的完整代码实现

// luogu-judger-enable-o2
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
using namespace __gnu_pbds;

inline int read() {
    int x = 0;
    char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x;
}

struct job {
    int end_time;
    int value;
} j[100005];

struct cmp{
    inline bool operator() (const job& J1, const job& J2){
        if (J1.value != J2.value) return J1.value > J2.value;
        return J1.end_time > J2.end_time;
    }
};

gp_hash_table<int, int> pr;
gp_hash_table<int, int> time_table;
int main() {
    int n = read();
    for (register int i = 1; i <= n; ++i) {
        j[i].end_time = read();
        j[i].value = read();
    }
    sort(j + 1, j + n + 1, cmp());
    long long ans = 0;
    for (register int i = 1; i <= n; ++i) {
        int now_time = j[i].end_time;
        while ( pr[ j[i].end_time ] && j[i].end_time > 0) {
            if(time_table[ j[i].end_time ])
                j[i].end_time = time_table[ j[i].end_time ]--;
            else j[i].end_time--;
        }
        time_table[now_time] = j[i].end_time;
        if ( j[i].end_time ) {
            ans += j[i].value;
            pr[ j[i].end_time ] = 1;
        }
    }
    printf("%lld\n", ans);
    return 0;
}
posted @ 2019-08-13 16:23  zs__std  阅读(204)  评论(0)    收藏  举报