单调队列优化多重背包

思路

这里只是贴一下 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;
}
posted @ 2019-08-11 10:19  featherZHY  阅读(115)  评论(0编辑  收藏  举报