似乎最好的方法是按大小对文件进行排序并进行处理。这种贪婪的做法可以解释为“先压缩小文件,避免先压缩大文件”。
可能的批准是:
如果我们有两个文件 A,B 使得 size(A)
t(A,B)
A/M + B/(M - L*A)
A*(1/M - 1/(M - L*B))
B/A >= (1/M - 1/(M - L*B)) / (1/M - 1/(M - L*A)) = B*(M - L*A) / (A*(M - L*B))
1 >= (M - L*A)/(M - L*B)
-L*B >= -L*A
B >= A
所以这意味着第一个方程式也是正确的(如果没有在某处失败:D)
排序为我们提供了每对文件 A
我为 N
测试:N、L、M、K 和 N 个文件
8 0.5 80.0 1.0
7 1 6 3 4 5 6 5
结果:
0.515769
1 3 4 5 5 6 6 7
#include <iostream>
#include <algorithm>
using namespace std;
// will work bad for cnt > 10 because 10! = 3628800
int perm[] = {0,1,2,3,4,5,6,7,8,9};
int bestPerm[10];
double sizes[10];
double calc(int cnt, double L, double M, double K, double T) {
double res = 0.0, usedMemory = 0.0;
for(int i = 0; i < cnt; i++) {
int ind = perm[i];
res += K * sizes[ind] / (M - L * usedMemory - (T - usedMemory));
usedMemory += sizes[ind];
}
return res;
}
int main() {
int cnt;
double L,M,K,T = 0.0;
cin >> cnt >> L >> M >> K;
for(int i = 0; i < cnt; i++)
cin >> sizes[i], T += sizes[i];
double bruteRes = 1e16;
int bruteCnt = 1;
for(int i = 2; i <= cnt; i++)
bruteCnt *= i;
for(int i = 0; i < bruteCnt; i++) {
double curRes = calc(cnt, L, M, K, T);
if( bruteRes > curRes ) {
bruteRes = curRes;
for(int j = 0; j < cnt; j++)
bestPerm[j] = perm[j];
}
next_permutation(perm, perm + cnt);
}
cout << bruteRes << "\n";
for(int i = 0; i < cnt; i++)
cout << sizes[bestPerm[i]] << " ";
cout << "\n";
return 0;
}
更新当所有文件pastebin L 不同时的实现(似乎蛮力更喜欢按压缩比 L[i] 的降序对它们进行排序并首先使用较小的文件,如果 L 相等)。