首页 > 其他分享 >动态规划——矩阵优化DP 学习笔记

动态规划——矩阵优化DP 学习笔记

时间:2023-09-27 14:12:06浏览次数:42  
标签:begin end text 矩阵 笔记 times Base bmatrix DP

动态规划——矩阵优化DP 学习笔记

前置知识:矩阵、矩阵乘法

矩阵乘法优化线性递推

斐波那契数列

在斐波那契数列当中,\(f_1 = f_2 = 1\),\(f_i = f_{i - 1} + f_{i - 2}\),求 \(f_n\)。

而分析式子可以知道,求 \(f_k\) 仅与 \(f_{k - 1}\) 和 \(f_{k - 2}\) 有关;
所以我们设矩阵 \(F_i = \begin{bmatrix} f_{i - 1} & f_{i - 2} \end{bmatrix}\)。

设矩阵 \(\text{Base}\),使得 \(F_{i - 1} \times \text{Base} = F_i\),接下来考虑 \(\text{Base}\) 是什么;
带入可得 \(\begin{bmatrix} f_{i - 2} & f_{i - 3} \end{bmatrix} \times \text{Base} = \begin{bmatrix} f_{i - 1} & f_{i - 2} \end{bmatrix}\)。

即 \(\begin{bmatrix} f_{i - 2} & f_{i - 3} \end{bmatrix} \times \text{Base} = \begin{bmatrix} f_{i - 2} + f_{i - 3} & f_{i - 2} \end{bmatrix}\);
根据矩阵乘法的规则可知 \(\text{Base}\) 的第 \(1\) 列应为 \(\begin{bmatrix} 1 & 1 \end{bmatrix}^\text{T}\),第 \(2\) 列应为 \(\begin{bmatrix} 1 & 0 \end{bmatrix}^\text{T}\)。

所以求得 \(\text{Base} = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}\)。

然后考虑 \(f_i\) 的值应该是多少;
根据前面的公式可以知道 \(f_i = F_{n + 1}\) 的第一个数,所以就是求这个数。

根据 \(f_1 = f_2 = 1\),可以知道 \(F_3 = \begin{bmatrix} f_2 & f_1 \end{bmatrix} = \begin{bmatrix} 1 & 1 \end{bmatrix}\),我们将这个作为边界值;
然后有 \(F_4 = F_3 \times \text{Base}\),\(F_5 = F_4 \times \text{Base} = F_3 \times \text{Base} \times \text{Base}\)。

因为矩阵乘法有结合律,所以 \(F_{n + 1} = F_3 \times \text{Base}^{n - 2} = \begin{bmatrix} 1 & 1 \end{bmatrix} \times \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}^{n - 2}\)。

因为矩阵没有交换律,所以 \(F_3\)(前)和 \(\text{Base}^{n - 2}\)(后)一定不能写反了!

例题1

\(\left\{\begin{array}{l} f_1 = f_2 = 0 \\ f_i = f_{i - 1} + f_{i - 2} + 1 \end{array}\right.\)

点击查看题解

\(f_i\) 仅与 \(f_{i - 1}\) 和 \(f_{i - 2}\) 有关,同时还包括了常数 \(1\),
所以我们设 \(F_i = \begin{bmatrix} f_{i - 1} & f_{i - 2} & 1 \end{bmatrix}\),

然后设 \(\text{Base}\) 使得 \(F_{i - 1} \times \text{Base} = F_i\),
即 \(\begin{bmatrix} f_{i - 2} & f_{i - 3} & 1 \end{bmatrix} \times \text{Base} = \begin{bmatrix} f_{i - 1} & f_{i - 2} & 1 \end{bmatrix}\)。

因为 \(f_{i - 1} = f_{i - 2} + f_{i - 3} + 1\),所以易知:

\(\text{Base} = \begin{bmatrix} 1 & 1 & 0 \\ 1 & 0 & 0 \\ 1 & 0 & 1 \end{bmatrix}\).

边界条件为 \(F_3 = \begin{bmatrix} 0 & 0 & 1\end{bmatrix}\),
所以 \(F_{n + 1} = F_3 \times \text{Base}^{n - 2}\)。

即可求出 \(f_n\).

例题2

\(\left\{\begin{array}{l} f_1 = 0 \text{,} f_2 = 1 \\ f_i = f_{i - 1} + f_{i - 2} + i \end{array}\right.\)

点击查看题解

\(f_i\) 仅与 \(f_{i - 1}\)、\(f_{i - 2}\) 和 \(i\) 有关,为实现 \(i\) 的递增,还需设置常量 \(1\);
所以我们设 \(F_i = \begin{bmatrix} f_{i - 1} & f_{i - 2} & i & 1 \end{bmatrix}\),

由 \(F_{i - 1} \times \text{Base} = F_i\) 得 \(\text{Base} = \begin{bmatrix} 1 & 1 & 0 & 0 \\ 1 & 0 & 0 & 0 \\ 1 & 0 & 1 & 0 \\ 0 & 0 & 1 & 1 \end{bmatrix}\).

边界条件为 \(F_3 = \begin{bmatrix} 1 & 0 & 3 & 1 \end{bmatrix}\).

\(F_{n + 1} = F_3 \times \text{Base}^{n - 2}\);即可求出 \(f_n\)。

例题3(来自 OI-Wiki)

\(\left\{\begin{array}{l} f_{1} = f_{2} = 0 \\ f_{n} = 7f_{n-1}+6f_{n-2}+5n+4\times 3^n \end{array}\right.\)

点击查看题解

我的解法与 OI-Wiki 上的有所不同:

设 \(F_n = \begin{bmatrix} f_{n - 1} & f_{n - 2} & n & 3^n & 1 \end{bmatrix}\).

易知 \(\text{Base} = \begin{bmatrix} 7 & 1 & 0 & 0 & 0 \\ 6 & 0 & 0 & 0 & 0 \\ 5 & 0 & 1 & 0 & 0 \\ 4 & 0 & 0 & 3 & 0 \\ 0 & 0 & 1 & 0 & 1 \end{bmatrix}\).

边界值 \(F_3 = \begin{bmatrix} 0 & 0 & 3 & 27 & 1 \end{bmatrix}\).

则 \(F_{n + 1} = F_3 \times \text{Base}^{n - 2}\).

例题4

\(\left\{\begin{array}{l} f_1 = f_2 = 0 \text{,} f_3 = 1 \\ f_i = 3f_{i - 1} + 2f_{i - 2} + f_{i - 3} + 5i + 7 \end{array}\right.\)

点击查看题解

增加了 \(f_{i - 3}\),但是本质是一样的。

可以设 \(F_i = \begin{bmatrix} f_{i - 1} & f_{i - 2} & f_{i - 3} & i & 1 \end{bmatrix}\),

易得 \(\text{Base} = \begin{bmatrix} 3 & 1 & 0 & 0 & 0 \\ 2 & 0 & 1 & 0 & 0 \\ 1 & 0 & 0 & 0 & 0 \\ 5 & 0 & 0 & 1 & 0 \\ 7 & 0 & 0 & 1 & 1 \end{bmatrix}\).

而 \(F_4 = \begin{bmatrix} 1 & 0 & 0 & 4 & 1 \end{bmatrix}\),

则 \(F_{n + 1} = F_4 \times \text{Base}^{n - 3}\)。

例题5

洛谷 P1939 矩阵加速(数列):https://www.luogu.com.cn/problem/P1939

考虑这道题 \(\text{Base}\) 该如何设置。

点击查看代码
#include <bits/stdc++.h>

#define rr read()

using namespace std;

const long long MOD = 1e9 + 7;

inline int read()
{
    int num = 0, flag = 1;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar())
        if (ch == '-')
            flag = -1;
    for (; isdigit(ch); ch = getchar())
        num = (num << 3) + (num << 1) + ch - '0';
    return num * flag;
}

struct matrix
{
    long long a[4][4];
    matrix operator*(const matrix &t) const
    {
        matrix res;
        memset(res.a, 0, sizeof res.a);
        for (int i = 1; i <= 3; ++i)
            for (int j = 1; j <= 3; ++j)
                for (int k = 1; k <= 3; ++k)
                    res.a[i][j] = (res.a[i][j] + a[i][k] * t.a[k][j] % MOD) % MOD;
        return res;
    }
};

int main()
{
    int T = rr;
    while (T--)
    {
        int n = rr;

        if (n <= 3)
        {
            printf("1\n");
            continue;
        }

        matrix Base = {{{0, 0, 0, 0},
                        {0, 1, 1, 0},
                        {0, 0, 0, 1},
                        {0, 1, 0, 0}}};
        matrix res = {{{0, 0, 0, 0},
                       {0, 1, 0, 0},
                       {0, 0, 1, 0},
                       {0, 0, 0, 1}}};

        int k = n - 3;
        while (k)
        {
            if (k & 1)
                res = res * Base;
            k >>= 1, Base = Base * Base;
        }

        printf("%lld\n", (res.a[1][1] + res.a[2][1] + res.a[3][1]) % MOD);
    }

    return 0;
}

时间复杂度

矩阵乘法 \(O(k^3)\) 其中 \(k\) 为矩阵的长(或宽);
快速幂 \(O(\log n)\);

所以[矩阵乘法优化线性递推]的时间复杂度为 \(O(k^3 \log n)\)。

矩阵乘法优化 DP

朴素矩阵乘法

有 \(\mathrm{dp}[t][x][y] = \sum\limits_{w = 1}^n \mathrm{dp}[t][x][w] \times G[w][y]\),

则可以看为矩阵乘法的形式:\(\mathrm{dp}_t = \mathrm{dp}_{t - 1} \times G\),即 \(\mathrm{dp}_t = Ans_0 \times G^t\)。

广义矩阵乘法

考虑将原公式推广,即广义矩阵乘法:对于矩阵 \(A_{n \times m}\) 和 \(B_{m \times r}\):

有 \(C_{ij} = A \times B = \bigoplus\limits_{k = 1}^m \, (A_{ik} \otimes B_{kj})\),我们将其成为 \((\otimes, \; \oplus)\) 的矩阵乘法。

当满足以下条件时,广义矩阵乘法满足结合律:

  • \(\otimes\) 具有结合律和交换律;
  • \(\otimes\) 对 \(\oplus\) 存在分配律,即满足 \((a \oplus b) \otimes c = (a \otimes c) \oplus (b \otimes c)\)。

常见的矩阵乘法形式有 \((\pm, \; \max)\)、\((\pm, \; \min)\)、\((\land, \; \lor)\)。

然后对矩阵的乘法重载为此解法即可用快速幂求解了,具体的可以看这篇文章:https://www.luogu.com.cn/blog/i207M/xie-ti-bao-gao-sp1716-gss3-can-you-answer-these-queries-iii

多组询问的矩阵乘法优化 DP

例题:P6569 魔法值

我们要求一个 \(\mathrm{Ans}_k = \mathrm{Ans}_0 \times \mathrm{Mp}^k\),其中 \(\mathrm{Ans}_i\) 是一个长度为 \(n\) 的行向量。

那么,我们先预处理 \(\mathrm{Mp}^k\),即 \(\mathrm{Mp}^{2^i}\)。

然后我们就是在求一个行向量和 \(\log_2 k\) 个 \(n \times n\) 的矩阵的乘积了。

在算答案的时候,我们先别算这 \(\log_2 k\) 个方阵的乘积,先用 \(\mathrm{Ans}_0\) 向量从左乘到右。

因为向量乘矩阵复杂度是 \(O(n^2)\) 的!

这样复杂度就从 \(O(q \times n^3 \log_2 t)\),变成了 \(O(n^3 \log_2 t+q \times n^2 \log_2 t)\)。

Reference

[1] https://oi-wiki.org/math/linear-algebra/matrix/
[2] https://www.cnblogs.com/ningago/p/17472070.html
[3] https://www.cnblogs.com/luckyblock/p/14430820.html
[4] http://blog.tsawke.com/Data/Blog/content/DDP.html
[5] https://blog.csdn.net/qq_41739081/article/details/128184363

标签:begin,end,text,矩阵,笔记,times,Base,bmatrix,DP
From: https://www.cnblogs.com/RainPPR/p/matrix-dp.html

相关文章

  • UDP之组播
    UDP单播这篇写了UDP单播,接下来深入一点,写一下UDP组播UDP其实还有一个广播,其实也很极端,会向局域网内所有主机广播数据。有的时候我们只想向特定几个主机发送数据,那么只能用组播。组播需要使用组播地址,在IPv4中它的范围从224.0.0.0到239.255.255.255,并被划分为局部链接多播地......
  • 线程池ThreadPool
    1什么是线程池?ThreadPool类命名空间:System.Threading程序集:System.Threading.ThreadPool.dll提供一个线程池,该线程池可用于执行任务、发送工作项、处理异步I/O、代表其他线程等待以及处理计时器。 * 通过线程池创建的线程默认为后台线程,优先级默认为Normal。 ......
  • Vue2.0 浅学笔记
    Vue是框架,也是生态。1.VueAPI风格选项式(Vue2)组合式(Vue3)2.入门node.js版本大于153.创建项目创建项目npminitvue@latest开发环境VScode+Volar4.基本语法1.文本插值仅能使用单一表达式使用JavaScript表达式每个绑定仅支持单一表达式,也就是一段能够被求值的J......
  • EMQX学习笔记:命令行工具
    本文更新于2023-02-28,使用EMQX4.4.3。目录emqxemqx_ctlemqx官方文档:https://www.emqx.io/docs/zh/v4.4/getting-started/command-line.htmlemqxconsole:控制台模式。emqxrestart:重启EMQX。emqxstart:启动EMQX。emqx_ctl官方文档:https://www.emqx.io/docs/zh/v4.4/adva......
  • MMU复习--Apple的学习笔记
    一,前言以前看过MMU,因为这是单片机OS中没有的,当时我记得理解的不是很清晰,包括MMU中哪部分是硬件的,哪部分是软件的都没有太搞清楚。由于看了一个自己写linux操作系统的视频,里面有介绍MMU,且演示了虚拟地址和物理地址的转换,此时我才深刻的理解了,所以在看qemu源码的内存管理前,我先复习......
  • MMU复习--Apple的学习笔记
    一,前言以前看过MMU,因为这是单片机OS中没有的,当时我记得理解的不是很清晰,包括MMU中哪部分是硬件的,哪部分是软件的都没有太搞清楚。由于看了一个自己写linux操作系统的视频,里面有介绍MMU,且演示了虚拟地址和物理地址的转换,此时我才深刻的理解了,所以在看qemu源码的内存管理前,我先复习下......
  • 《Java编程思想第四版》学习笔记31--关于Externalizable
    //:Blip3.java//Reconstructinganexternalizableobjectimportjava.io.*;importjava.util.*;classBlip3implementsExternalizable{inti;Strings;//NoinitializationpublicBlip3(){System.out.println("Blip3Constructor");//s,inoti......
  • JMockit学习笔记
    1基本概念1.1常用注解@Mocked:被修饰的对象将会被Mock,对应的类和实例都会受影响(同一个测试用例中)@Injectable:仅Mock被修饰的对象@Capturing:可以mock接口以及其所有的实现类@Mock:MockUp模式中,指定被Fake的方法1.2常用的类Expectations:期望,指定的方法必须被调用StrictExpectati......
  • k8s笔记15
    摘要:CephOSDStatusoutdown;k8s笔记1(知识图谱,添加节点,ceph存储)_ATCtoK8s空管智能运维的技术博客_51CTO博客【ceph】cephOSD状态及常用命令-bdy-博客园(cnblogs.com)ceph集群磁盘故障,更换磁盘流程-腾讯云开发者社区-腾讯云(tencent.com)1、CephDashboard的Cluster>>OSD......
  • 动态规划——状压DP 学习笔记
    动态规划——状压DP学习笔记引入前置知识:位运算动态规划的过程是随着阶段的增长,在每个状态维度上不断扩展的。在任意时刻,已经求出最优解的状态与尚未求出最优解的状态在各维度上的分界点组成了DP扩展的“轮廓”。对于某些问题,我们需要在动态规划的“状态”中记录一个集合......