【矩阵快速幂】封装类及测试用例及样例

简介: 【矩阵快速幂】封装类及测试用例及样例

封装类

核心代码

class CMat
{
public:
  // 矩阵乘法
  static vector<vector<long long>> multiply(const vector<vector<long long>>& a, const vector<vector<long long>>& b) {
    const int r = a.size(), c = b.front().size(),iK = a.front().size();
    assert(iK == b.size());
    vector<vector<long long>> ret(r, vector<long long>(c));
    for (int i = 0; i < r; i++)
    {
      for (int j = 0; j < c ; j++) 
      {
        for (int k = 0; k < iK; k++)
        {
          ret[i][j] = (ret[i][j] + a[i][k] * b[k][j] ) % s_llMod;
        }
      }
    }
    return ret;
  }
  // 矩阵快速幂
  static vector<vector<long long>> pow( const vector<vector<long long>>& a, vector<vector<long long>> b, long long n) {
    vector<vector<long long>> res = a;
    for (; n; n /= 2) {
      if (n % 2) {
        res = multiply(res, b);
      }
      b = multiply(b, b);
    }
    return res;
  }
  static vector<vector<long long>> TotalRow(const vector<vector<long long>>& a)
  {
    vector<vector<long long>> b(a.front().size(), vector<long long>(1, 1));
    return multiply(a, b);
  }
protected:
  const static long long s_llMod = 1e9 + 7;
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{
  assert(t1 == t2);
}
template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
  if (v1.size() != v2.size())
  {
    assert(false);
    return;
  }
  for (int i = 0; i < v1.size(); i++)
  {
    Assert(v1[i], v2[i]);
  }
}
int main()
{
  vector<vector<long long>> pre = { {1,2} };
  vector<vector<long long>> mat = { {2,3},{1,10} };
  { 
    auto res = CMat::pow(pre, mat, 0);
    Assert(pre, res);
  }
  {
    auto res = CMat::multiply(pre, mat);
    Assert(vector<vector<long long>>{ {4, 23}}, res);
    auto res2 = CMat::pow(pre, mat,1);
    Assert(res2, res);
  }
  {
    auto res = CMat::pow(pre, mat, 2);
    auto res1 = CMat::multiply(pre, mat);
    auto res2 = CMat::multiply(res1, mat);
    Assert(res2, res);
    Assert(vector<vector<long long>>{ {31, 242}}, res);
  };
  for (int i = 3; i < 100; i++)
  {
    auto res = pre;
    for (int j = 0; j < i; j++)
    {
      res = CMat::multiply(res, mat);
    }
    auto res2 = CMat::pow(pre, mat, i);
    Assert(res2, res);
  }
}

具体例子

题目、分析和原理见:

【动态规划】【矩阵快速幂】【滚动向量】C++算法552. 学生出勤记录 II

原解法用二维表示状态,改成一维。 i是缺勤数量,j是连续迟到数,新的状态为:3*i+j

6种状态,故转移矩阵为6行6列,故结果矩阵为6列,6个数据1行就足够了。

令旧结果矩阵为mat1,转移矩阵为mat2,新矩阵为mat3,K mat1的列数,mat2的行数。则:

mat3[r][c] = Sum[ 0 , k ) i ^{i}_{[0,k)}[0,k)i(mat1[r][i]*mat2[i][c])

i在mat1中列号,在mat2中是行号。 也就是旧状态在第几列,mat2就在第几行。

新状态就是mat2的行号。

class Solution {
public:
  int checkRecord(int n) {
    vector<vector<long long>> pre(1, vector<long long>(6));//1行6列 
    pre[0][0] = 1;
    vector<vector<long long>> mat(6, vector<long long>(6));
    { 
      //之前的状态在pre是第几列,矩阵中就是第几行。新状态的列号就矩阵的列号
      //处理一次缺勤 ,缺勤两次排除
      for (int i = 0; i < 3; i++)
      {
        mat[i][3]++;
      }
      //处理请假
      for (int i = 0; i < 2; i++)
      {
        for (int j = 0; j < 2; j++)
        {
          const int pre = 3 * i + j;
          mat[pre][pre + 1]++;
        }
      }
      //处理正常
      for (int i = 0; i < 2; i++)
      {
        for (int j = 0; j < 3; j++)
        {
          const int pre = 3 * i + j;
          const int cur = 3 * i;
          mat[pre][cur]++;
        }
      }
    }
    auto res = CMat::pow(pre, mat, n);
    res = CMat::TotalRow(res);
    return res[0][0];
  }
};

测试用例

template
void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}
template
void Assert(const vector& v1, const vector& v2)
{
if (v1.size() != v2.size())
{
assert(false);
return;
}
for (int i = 0; i < v1.size(); i++)
{
Assert(v1[i], v2[i]);
}
}
int main()
{
int n;
{
Solution sln;
n = 0;
auto res = sln.checkRecord(n);
Assert(1, res);
}
{
Solution sln;
n = 1;
auto res = sln.checkRecord(n);
Assert(3, res);
}
{
Solution sln;
n = 2;
auto res = sln.checkRecord(n);
Assert(8, res);
}
{
Solution sln;
n = 3;
auto res = sln.checkRecord(n);
Assert(19, res);
}
{
Solution sln;
n = 4;
auto res = sln.checkRecord(n);
Assert(43, res);
}
{
Solution sln;
n = 5;
auto res = sln.checkRecord(n);
Assert(94, res);
}
{
Solution sln;
n = 6;
auto res = sln.checkRecord(n);
Assert(200, res);
}
{
Solution sln;
n = 7;
auto res = sln.checkRecord(n);
Assert(418, res);
}
{
Solution sln;
n = 10101;
auto res = sln.checkRecord(n);
Assert(183236316, res);
}
}


扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。

https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程

https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版

https://download.csdn.net/download/he_zhidan/88348653

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 **C+

+17**

如无特殊说明,本算法用**C++**实现。

相关文章
|
13天前
|
Java 程序员 测试技术
Java|让 JUnit4 测试类自动注入 logger 和被测 Service
本文介绍如何通过自定义 IDEA 的 JUnit4 Test Class 模板,实现生成测试类时自动注入 logger 和被测 Service。
20 5
|
1月前
|
测试技术 开发者
vertx的学习总结6之动态代理类和测试
本文是Vert.x学习系列的第六部分,介绍了如何使用动态代理在事件总线上公开服务,以及如何进行Vert.x组件的异步测试,包括动态代理的创建和使用,以及JUnit 5和Vert.x测试工具的结合使用。
18 3
vertx的学习总结6之动态代理类和测试
|
2月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
43 2
|
3月前
|
JSON 测试技术 数据格式
单元测试问题之使用JCode5插件生成测试类如何解决
单元测试问题之使用JCode5插件生成测试类如何解决
110 3
|
3月前
|
Java 测试技术 Spring
单元测试问题之在 JCode5 类中使用 testService如何解决
单元测试问题之在 JCode5 类中使用 testService如何解决
23 2
|
4月前
|
测试技术
详解单元测试问题之MockHandlerImpl类的handle方法中VerificationMode不为空如何解决
详解单元测试问题之MockHandlerImpl类的handle方法中VerificationMode不为空如何解决
55 3
|
4月前
|
Java 数据库 Spring
Java编程问题之在测试中使用CGLIB创建代理类如何解决
Java编程问题之在测试中使用CGLIB创建代理类如何解决
|
25天前
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
46 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
|
2月前
|
移动开发 JSON Java
Jmeter实现WebSocket协议的接口测试方法
WebSocket协议是HTML5的一种新协议,实现了浏览器与服务器之间的全双工通信。通过简单的握手动作,双方可直接传输数据。其优势包括极小的头部开销和服务器推送功能。使用JMeter进行WebSocket接口和性能测试时,需安装特定插件并配置相关参数,如服务器地址、端口号等,还可通过CSV文件实现参数化,以满足不同测试需求。
212 7
Jmeter实现WebSocket协议的接口测试方法
|
2月前
|
JSON 移动开发 监控
快速上手|HTTP 接口功能自动化测试
HTTP接口功能测试对于确保Web应用和H5应用的数据正确性至关重要。这类测试主要针对后台HTTP接口,通过构造不同参数输入值并获取JSON格式的输出结果来进行验证。HTTP协议基于TCP连接,包括请求与响应模式。请求由请求行、消息报头和请求正文组成,响应则包含状态行、消息报头及响应正文。常用的请求方法有GET、POST等,而响应状态码如2xx代表成功。测试过程使用Python语言和pycurl模块调用接口,并通过断言机制比对实际与预期结果,确保功能正确性。
223 3
快速上手|HTTP 接口功能自动化测试