题目
思路
思路见背包九讲。
刚开始考虑直接用stl的queue实现,vijos的第一个题解也是这么实现的,但是仔细一看好像
O(NVK)
O
(
N
V
K
)
好像不太行,然后vijosAC,洛谷一半的点TLE了。
后面手动用数组实现了一下队列,洛谷也AC了。
这里的问题就是STL的使用,对于复杂度不是很紧的题目,STL可以随便用。但是对于本题洛谷的数据,NVK乘起来就已经50000000的级别,再使用STL,就导致一半的点AC,另一半的还大多都是900ms+这样。
而使用数组实现以后,就真的是常数级别,最大的点也在300ms以下。
望注意
还有一些细节看代码
代码
STL队列
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int INF = 100000;
const int maxk = 50 + 10;
const int maxm = 5000 + 10;
queue<int> q1, q2;
int k, c, n, v, w, d[maxm][maxk];
int main() {
scanf("%d%d%d", &k, &c, &n);
_rep(i, 0, c) _for(j, 0, k) d[i][j] = -INF; // 本题属于物体体积需要恰好等于背包容量的题,所以要初始化-INF
d[0][0] = 0;
_for(i, 0, n) {
scanf("%d%d", &v, &w);
for (int j = c; j >= v; j--) {
// 合并两个队列 d[j]和d[j-v]+w,并选出前k个最优解
_for(l, 0, k) {
q1.push(d[j][l]);
q2.push(d[j - v][l] + w);
}
_for(l, 0, k) {
if (q1.front() > q2.front()) {
d[j][l] = q1.front();
q1.pop();
}
else {
d[j][l] = q2.front();
q2.pop();
}
}
while (!q1.empty()) q1.pop(); // 队列没有自己的clear函数,所有要手动清空
while (!q2.empty()) q2.pop();
}
}
int ans = 0;
_for(l, 0, k) if (k >= 0 ) ans += d[c][l];
printf("%d\n", ans);
return 0;
}
数组实现
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int INF = 100000;
const int maxk = 50 + 10;
const int maxm = 5000 + 10;
int q1[maxk], q2[maxk];
int k, c, n, v, w, d[maxm][maxk];
int main() {
scanf("%d%d%d", &k, &c, &n);
_rep(i, 0, c) _for(j, 0, k) d[i][j] = -INF; // 本题属于物体体积需要恰好等于背包容量的题,所以要初始化-INF
d[0][0] = 0;
_for(i, 0, n) {
scanf("%d%d", &v, &w);
for (int j = c; j >= v; j--) {
// 合并两个队列 d[j]和d[j-v]+w,并选出前k个最优解
_for(l, 0, k) {
q1[l] = d[j][l];
q2[l] = d[j - v][l] + w;
}
int len1 = 0, len2 = 0;
_for(l, 0, k) {
if (q1[len1] > q2[len2]) {
d[j][l] = q1[len1];
len1++;
}
else {
d[j][l] = q2[len2];
len2++;
}
}
}
}
int ans = 0;
_for(l, 0, k) if (k >= 0) ans += d[c][l];
printf("%d\n", ans);
return 0;
}