洛谷P2949 工作调度Work Scheduling题解
题目链接 :洛谷P2949
这道题目是一道很明显的贪心问题。可以发现每个工作代价(占用时间)均为一,而相应的价值(工作利润)不同。此时我们可以想到一个很显然的贪心策略,即
- 当工作的利润不同时,优先进行利润更大的工作
- 当工作的利润相同时,优先进行截止时间更晚的工作
根据以上贪心策略,对于工作,可以定义以下结构体
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; }
浙公网安备 33010602011771号