单调队列优化多重背包
这里只是贴一下 JZOJ4224.食物 的代码,挺有意思的水题,虽然一眼就看得出来两个多重背包,但是在处理交通工具时为了求出答案,把价格当做体积,把最大装载量当做价值。一切思路还是为了答案服务,这是值得记录的。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2100;
const int MAX = 2000000 + 10;
int t, n, m, p, l, r, num[N], v[N], w[N], maxx[N], price[N], sum[N], V, f[MAX], f1[MAX];
struct node
{
int po, val;
}q[MAX];
void bag()
{
for (int i = 1; i <= m; i++)
{
sum[i] = min(sum[i], 50000 / price[i]);
for (int b = 0; b < price[i]; b++)
{
l = r = 1;
int a = (50000 - b) / price[i];
for (int k = 0; k <= a; k++)
{
int y = f[k * price[i] + b] - k * maxx[i];
while (l < r && q[r - 1].val <= y) r--;
q[r].po = k;
q[r++].val = y;
while (l < r && q[l].po < k - sum[i]) l++;
f[k * price[i] + b] = max(q[l].val + k * maxx[i], f[k * price[i] + b]);
}
}
}
}
void bag1()
{
V = p + 100;
for (int i = 1; i <= n; i++)
{
num[i] = min(num[i], V / v[i]);
for (int b = 0; b < v[i]; b++)
{
l = r = 1;
int a = (V - b) / v[i];
for (int k = 0; k <= a; k++)
{
int y = f1[k * v[i] + b] - k * w[i];
while (l < r && q[r - 1].val <= y) r--;
q[r].po = k;
q[r++].val = y;
while (l < r && q[l].po < k - num[i]) l++;
f1[k * v[i] + b] = max(f1[k * v[i] + b], q[l].val + k * w[i]);
}
}
}
for (int i = 1; i <= 50000; i++)
if (f1[f[i]] >= p)
{
printf("%d\n", i);
return;
}
printf("TAT\n");
return;
}
int main()
{
scanf("%d", &t);
for (int o = 1; o <= t; o++)
{
memset(f, 0, sizeof f);
memset(f1, 0, sizeof f1);
scanf("%d%d%d", &n, &m, &p);
for (int i = 1; i <= n; i++)
scanf("%d%d%d", &w[i], &v[i], &num[i]);
for (int i = 1; i <= m; i++)
scanf("%d%d%d", &maxx[i], &price[i], &sum[i]);
bag();
bag1();
}
return 0;
}