• 使用单调队列优化的 O(nm) 多重背包算法


    我搜索了一下,找到了一篇很好的博客,讲的挺详细:链接

    解析

    多重背包的最原始的状态转移方程:

    令 c[i] = min(num[i], j / v[i])

    f[i][j] = max(f[i-1][j-k*v[i]] + k*w[i])     (1 <= k <= c[i])  这里的 k 是指取第 i 种物品 k 件。

    如果令 a = j / v[i] , b = j % v[i] 那么 j = a * v[i] + b.

    这里用 k 表示的意义改变, k 表示取第 i 种物品的件数比 a 少几件。

    那么 f[i][j] = max(f[i-1][b+k*v[i]] - k*w[i]) + a*w[i]      (a-c[i] <= k <= a)

    可以发现,f[i-1][b+k*v[i]] - k*w[i] 只与 k 有关,而这个 k 是一段连续的。我们要做的就是求出 f[i-1][b+k*v[i]] - k*w[i] 在 k 取可行区间内时的最大值。

    这就可以使用单调队列优化。

    代码

    其中 Q1 是一个用来存储可用状态的队列, Q2 是单调队列。

    //f[i][j] = max(f[i-1][b+k*v[i]] - k*w[i]) + a*w[i]   (a-c[i] <= k <= a)
    
    for (int i = 1; i <= n; ++i) {
    	Ni = Num[i]; Vi = V[i]; Wi = W[i];
    	for (int j = 0; j < Vi; ++j) {
    		Head1 = Tail1 = 0;
    		Head2 = Tail2 = 0;
    		Cnt = 0;
    		for (int k = j; k <= m; k += Vi) {
    			if (Tail1 - Head1 == Ni + 1) {
    				if (Q2[Head2 + 1] == Q1[Head1 + 1]) ++Head2;
    				++Head1;
    			}
    			t = f[k] - Cnt * Wi;
    			Q1[++Tail1] = t;
    			while (Head2 < Tail2 && Q2[Tail2] < t) --Tail2;
    			Q2[++Tail2] = t;
    			f[k] = Q2[Head2 + 1] + Cnt * Wi; 
    			++Cnt;
    		}
    	}
    }

    例题:HDOJ - 1171

  • 相关阅读:
    0603 学术诚信与道德
    0601 新的冲刺
    0525 Scrum 项目7.0
    0523 Scrum 项目6.0
    0518 Scrum项目5.0
    0512 Scrum 4.0
    0512 操作系统之进程调度
    0511 backlog
    0506 Scrum 项目1.0
    复利计算再升级
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4165956.html
Copyright © 2020-2023  润新知