点击前往试题目录:https://blog.csdn.net/best335/article/details/99550556
如果你确实想解出题,你可以搜索 KD-Tree、三维偏序、CDQ分治 。
我的思路:这道题需要你不断地减少搜索范围也就是剪枝。
**或者想象使两个CPU设备差值最小的背包问题,这很难建模 **
- 定义:
- C(使用一个CPU所用的时间)
- G (使用一个CPU和一个GPU所用的时间)
- CC(使用两个CPU或全部使用的最小值)
剪枝策略
- 同时使用两个CPU和使用全部设备是等价的,我们只需要取最小值。
- 对于min(C,G)<=CC的任务,我们只执行C或G
- 若C<=G,仅执行C
- 若C > G,执行C,G
- 对于sum( C )>sum( G )的只执行G
- 否则执行C,G,这里还可以优化。
- 对于min(C,G)>CC的任意两个任务
- 若min(C1,G1)+min(C2,G2)<=(CC1+CC2)/2+(CC1+CC2)%1,我们只执行他们的C或G。
- 否则我们执行C、G、CC
- 我们使用集合来最大限度的减少重复计算。
- 我们使用这样的排序策略:
- struct P{
int a,b,c,d;
bool operator < (const& P p)const{return a<p.a&&b<p.b&&c<p.c&&d<p.d;}
}
set< P > S; - 对于集合中任意两个对象p1,p2我们只是用p1!<p2的p1,用来优化插入的只有KD-tree了
- struct P{
- 我们使用这样的排序策略:
- 我们限制两个CPU使用时的差距不得超过 10*剩余的任务数
大概三分钟可以求出解
其中插入时间复杂度为O(n^3)
解题策略为分治+剪枝+插入优化
#pragma GCC optimize(2)
#include<iostream>
#include<unordered_set>
#define DEBUG
#ifdef DEBUG
#include<fstream>
#include<ctime>
#include<windows.h>
#endif
using namespace std;
inline int _abs(const int&a) {
return a<0 ? -a : a;
}
struct Task {
int C1, C2, G1, G2;
Task(const int& C1_, const int& C2_, const int& G1_, const int& G2_) :C1(C1_), C2(C2_), G1(G1_), G2(G2_) {
if (C1>C2) swap(C1, C2), swap(G1, G2);
}
};
inline bool operator==(const Task &t1, const Task &t2) {
return t1.C1 == t2.C1&&t1.C2 == t2.C2&&t1.G1 == t2.G1&&t1.G2 == t2.G2;
}
inline bool operator <(const Task& t1, const Task& t2) {
return t1.C1 <= t2.C1&&t1.C2 <= t2.C2&&t1.G1 <= t2.G1&&t1.G2 <= t2.G2;
}
struct Hasher {
size_t operator()(const Task &t) const noexcept {
return std::hash<long long>{}(t.C1 + t.C2 * 400L + t.G1 * 160000L + t.G2 * 64000000L);
}
};
struct Comparator {
bool operator()(const Task &t1, const Task &t2) const noexcept {
return t1.C1 == t2.C1&&t1.C2 == t2.C2&&t1.G1 == t2.G1&&t1.G2 == t2.G2;
}
};
unordered_set<Task, Hasher, Comparator> T[41];
int main() {
int n, ans = 400, H;
#ifdef DEBUG
ifstream cin("C:\\Users\\Isidore\\Desktop\\out.txt");
clock_t t1 = clock();
#endif
cin >> n, H = n * 10 + 1;
for (int i = 0, a, b, c, d, e, f; i<n; ++i) {
cin >> a >> b >> c >> d, e = min(a, c), f = min(b, d);//C > CG > CC = CCG 优先级
T[i].insert(Task(0, a, 0, 0));
if (f<e) T[i].insert(Task(f, f, b>d ? d : 0, b>d ? d : 0));
else if (c<a) T[i].insert(Task(0, c, 0, c));
}
for (short int i = 2, xi = 1; !T[xi].empty(); xi = i, i += i) {
for (short int j = 0, nj = min(40, n + xi); j + xi<nj; j += i) {
unordered_set<Task, Hasher, Comparator> List, &curr1 = T[j], &curr2 = T[j + xi];
cout << j <<" "<< j + xi<<" "<< curr1.size()<<" "<<curr2.size()<<" | ";
if (!curr1.empty() && !curr2.empty()) {
H -= 10;
for (const Task&t1 : curr1)
for (const Task&t2 : curr2) {
unordered_set<Task, Hasher, Comparator> proc;
if (_abs(t1.C1 + t2.C1 - t1.C2 - t2.C2)<H)
proc.insert(Task(t1.C1 + t2.C1, t1.C2 + t2.C2, t1.G1 + t2.G1, t1.G2 + t2.G2));
if (_abs(t1.C1 + t2.C2 - t1.C2 - t2.C1)<H)
proc.insert(Task(t1.C1 + t2.C2, t1.C2 + t2.C1, t1.G1 + t2.G2, t1.G2 + t2.G1));
for (auto itList = List.begin(); itList != List.end() && !proc.empty();) {
const Task & list = *itList;
bool F = true;
for (auto itCurr = proc.begin(); itCurr != proc.end();) {
const Task& curr = *itCurr;
if (list == curr || list<curr) proc.erase(itCurr++);
else if (curr<list) {
List.erase(itList++), F = false;
break;
}
else ++itCurr;
}
if (F) ++itList;
}
List.insert(proc.begin(), proc.end());
}
}
if(!List.empty()) T[j].swap(List);
curr2.clear();
}
cout << endl;
}
for (const Task&t : T[0]) ans = min(ans, max(max(t.C1, t.C2), t.G1 + t.G2));
cout << ans << endl;
#ifdef DEBUG
clock_t t2 = clock();
cout << T[n].size() << " " << t2 - t1 << "ms" << endl;
system("pause");
#endif
return 0;
}