首页 > 其他分享 >高斯消元和矩阵快速幂

高斯消元和矩阵快速幂

时间:2024-07-02 16:22:15浏览次数:19  
标签:begin end int 矩阵 bmatrix 快速 高斯消 式子

高斯消元

高斯消元是一种能在 \(O(N^3)\) 的时间内求解 \(N\) 元一次方程组的算法。

其思路大致如下:

  • 使第一个未知数只有第一个式子中系数非 \(0\)。
  • 使第二个未知数只有第二个式子中系数非 \(0\)。
  • \(\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \vdots\)
  • 使第 \(N\) 个未知数只有第 \(N\) 个式子中系数非 \(0\)。

在这时第 \(i\) 个未知数的解就为等号右边的数除以自己的系数。如果有式子无法满足,则无解或有无穷多解。

但如果是这样呢?

\[\begin{cases} x_2=0\\ x_1=0 \end{cases} \]

这样这种算法也会认为它不合法。所以当我们在让第 \(i\) 个未知数满足条件之前要先从后面的式子中找到一个满足条件的并交换即可。

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 105;
const long double EPS = 1e-6;

int n;
vector<long double> a[MAXN];

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n;
  for(int i = 1; i <= n; ++i) {
    a[i].resize(n + 2);
    for(int j = 1; j <= n + 1; ++j) {
      cin >> a[i][j];
    }
  }
  for(int i = 1; i <= n; ++i) {
    for(int j = i; j <= n; ++j) {
      if(fabs(a[j][i]) > EPS) {
        swap(a[i], a[j]);
        break;
      }
    }
    if(fabs(a[i][i]) <= EPS) {
      cout << "No Solution";
      return 0;
    }
    for(int j = 1; j <= n; ++j) {
      if(i != j) {
        long double res = 1.0l * a[j][i] / a[i][i];
        for(int k = 1; k <= n + 1; ++k) {
          a[j][k] -= 1.0l * a[i][k] * res;
        }
      }
    }
  }
  for(int i = 1; i <= n; ++i) {
    cout << 'x' << i << '=' << fixed << setprecision(2) << 1.0l * a[i][n + 1] / a[i][i] << "\n";
  }
  return 0;
}

拓展

当我们需要区分无解和无穷解时该怎么办呢?

我们就需要在交换式子时枚举所有的式子,如果这个式子中不应为 \(0\) 的未知数却为 \(0\) 或该式子在当前式子之后,那么就交换,并且当当前式子对应未知数为 \(0\) 时就不管他,直接 continue;

等消元完成后,如果发现式子左边为 \(0\) 而右边不为 \(0\),那么该方程组无解。如果发现式子左边为 \(0\) 而右边也为 \(0\),那么该方程组有无限组解。

注意:只要有一个式子发现无解就无解,即使既有无限解的式子又有无解的式子也是这样。

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 105;
const long double EPS = 1e-6;

int n;
vector<long double> a[MAXN];

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n;
  for(int i = 1; i <= n; ++i) {
    a[i].resize(n + 2);
    for(int j = 1; j <= n + 1; ++j) {
      cin >> a[i][j];
    }
  }
  for(int i = 1; i <= n; ++i) {
    for(int j = 1; j <= n; ++j) {
      if((j >= i || fabs(a[j][j]) <= EPS) && fabs(a[j][i]) > EPS) {
        swap(a[i], a[j]);
        break;
      }
    }
    if(fabs(a[i][i]) <= EPS) {
      continue;
    }
    for(int j = 1; j <= n; ++j) {
      if(i != j) {
        long double res = 1.0l * a[j][i] / a[i][i];
        for(int k = 1; k <= n + 1; ++k) {
          a[j][k] -= 1.0l * a[i][k] * res;
        }
      }
    }
  }
  for(int i = 1; i <= n; ++i) {
    bool op = 1;
    for(int j = 1; j <= n; ++j) {
      op &= (fabs(a[i][j]) <= EPS);
    }
    if(op && fabs(a[i][n + 1]) > EPS) {
      cout << "No Solution";
      return 0;
    }
  }
  for(int i = 1; i <= n; ++i) {
    bool op = 1;
    for(int j = 1; j <= n; ++j) {
      op &= (fabs(a[i][j]) <= EPS);
    }
    if(op && fabs(a[i][n + 1]) <= EPS) {
      cout << "Infinite Solution";
      return 0;
    }
  }
  for(int i = 1; i <= n; ++i) {
    cout << 'x' << i << '=' << fixed << setprecision(2) << 1.0l * a[i][n + 1] / a[i][i] << "\n";
  }
  return 0;
}

矩阵快速幂

首先介绍矩阵是什么以及四则运算。

矩阵就是一个 \(N\times M\) 的二维数组。

加减法:两个矩阵要做加减法必须满足两个矩阵的行和列相等,只需对对应的元素进行加减即可。如 \(\begin{bmatrix}1\ \ 2\\3\ \ 4\end{bmatrix}+\begin{bmatrix}5\ \ 6\\7\ \ 8\end{bmatrix}=\begin{bmatrix}6\ \ 8\\10\ 12\end{bmatrix}\)

乘法:设矩阵 \(A\) 大小为 \(N\times M\),矩阵 \(B\) 大小为 \(K\times N\),\(C=AB\),那么 \(C\) 的大小为 \(K\times M\) 且 \(C_{i,j}=\sum \limits_{k=1}^N A_{k,j}\cdot B_{i,k}\)。如 \(\begin{bmatrix}1\ \ 2\\3\ \ 4\end{bmatrix} \begin{bmatrix}5\ \ 6\\7\ \ 8\end{bmatrix}=\begin{bmatrix}23\ \ 34\\31\ \ 46\end{bmatrix}\)。

幂:设矩阵 \(A\) 大小为 \(N\times N\),那么 \(A^x=\underbrace{AAA\dots A}_ x\)。如 \(\begin{bmatrix}1\ \ 2\\3\ \ 4\end{bmatrix}^3=\begin{bmatrix}37\ \ 54\\81\ \ 118\end{bmatrix}\)。这里我们定义 \(A^0=\begin{bmatrix}1\ \ 0\ \ 0\ \ \cdots\ \ 0\\0\ \ 1\ \ 0\ \ \cdots\ \ 0\\0\ \ 0\ \ 1\ \ \cdots\ \ 0\\\vdots\ \ \vdots\ \ \vdots\ \ \ddots \ \ \vdots\\0\ \ 0\ \ 0\ \ \cdots\ \ 1\end{bmatrix}\),这个矩阵也是 \(N\times N\) 的。

代码

const int MAXN = 101;

struct Matrix {
  int n, m, mat[MAXN][MAXN];
  void clear(int a, int b) {
    n = a, m = b;
    for(int i = 1; i <= n; ++i) {
      for(int j = 1; j <= m; ++j) {
        mat[i][j] = 0;
      }
    }
  }
  void Set(int a) {
    n = m = a;
    for(int i = 1; i <= n; ++i) {
      for(int j = 1; j <= m; ++j) {
        mat[i][j] = (i == j);
      }
    }
  }
  Matrix operator*(const Matrix &a) {
    Matrix ans;
    ans.clear(a.n, m);
    for(int i = 1; i <= a.n; ++i) {
      for(int j = 1; j <= m; ++j) {
        for(int k = 1; k <= n; ++k) {
          ans.mat[i][j] += mat[k][j] * a.mat[i][k];
        }
      }
    }
    return ans;
  }
  Matrix operator*=(const Matrix &a) {
    return (*this = *this * a);
  }
};

Matrix Pow(const Matrix &a, int b) {
  Matrix res;
  res.Set(a.n);
  for(; b; a *= a, b >>= 1) {
    if(b & 1) {
      res *= a;
    }
  }
  return res;
}

应用

矩阵快速幂可以用来加速递推。比如:

求出斐波那契数列的第 \(N\) 项 \(\bmod (10^9+7)\) 的结果。\((1\le N \le 10^{18})\)

我们可以从这个角度来看:

设斐波那契数列的第 \(i\) 项为 \(f_i\)。如果我们知道了 \(f_{x-1},f_{x}\),我们怎么求 \(f_x,f_{x+1}\) 呢?

很容易可以得到:

\[\begin{cases} f_x=f_x\\ f_{x+1}=f_{x-1}+f_x \end{cases} \]

转换一下:

\[\begin{cases} f_x\ \ \ =0f_{x-1}+1f_x\\ f_{x+1}=1f_{x-1}+1f_x \end{cases} \]

我们可以再将式子转变为:

\[\begin{bmatrix}f_{x-1}\\f_x\end{bmatrix}\begin{bmatrix}0\ \ 1\\1\ \ 1\end{bmatrix}=\begin{bmatrix}f_x\\f_{x+1}\end{bmatrix} \]

所以我们可以得到斐波那契数列的第 \(N\) 项为矩阵 \(\begin{bmatrix}1\\1\end{bmatrix}\begin{bmatrix}0\ \ 1\\1\ \ 1\end{bmatrix}^{N-1}\) 的 \((1,1)\) 位置的元素。

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

const int MAXN = 3, MOD = int(1e9) + 7;

struct Matrix {
  int n, m, mat[MAXN][MAXN];
  void clear(int a, int b) {
    n = a, m = b;
    for(int i = 1; i <= n; ++i) {
      for(int j = 1; j <= m; ++j) {
        mat[i][j] = 0;
      }
    }
  }
  void Set(int a) {
    n = m = a;
    for(int i = 1; i <= n; ++i) {
      for(int j = 1; j <= m; ++j) {
        mat[i][j] = (i == j);
      }
    }
  }
  Matrix operator*(const Matrix &a) {
    Matrix ans;
    ans.clear(a.n, m);
    for(int i = 1; i <= a.n; ++i) {
      for(int j = 1; j <= m; ++j) {
        for(int k = 1; k <= n; ++k) {
          ans.mat[i][j] = (ans.mat[i][j] + 1ll * mat[k][j] * a.mat[i][k] % MOD) % MOD;
        }
      }
    }
    return ans;
  }
  Matrix operator*=(const Matrix &a) {
    return (*this = *this * a);
  }
}a, Mat;

ll n;

Matrix Pow(Matrix &a, int b) {
  Matrix res;
  res.Set(a.n);
  for(; b; a *= a, b >>= 1) {
    if(b & 1) {
      res *= a;
    }
  }
  return res;
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n;
  a.clear(2, 1), a.mat[1][1] = a.mat[2][1] = 1;
  Mat.clear(2, 2), Mat.mat[1][2] = Mat.mat[2][1] = Mat.mat[2][2] = 1;
  cout << (a * Pow(Mat, n - 1)).mat[1][1];
  return 0;
}

标签:begin,end,int,矩阵,bmatrix,快速,高斯消,式子
From: https://www.cnblogs.com/yaosicheng124/p/18280072

相关文章

  • 短视频矩阵/系统搭建/源码(HYT0606006)
    短视频矩阵的搭建通常涉及到内容管理系统(CMS)的集成、视频上传和管理功能、推荐算法、用户互动以及数据分析等多个组件。以下是构建短视频矩阵系统的一般步骤:需求分析:明确平台的目标用户、内容类型、功能需求,如社交分享、评论、点赞等。技术选型:选择后端框架(如Node.js、Pyth......
  • 快速调用 GLM-4-9B-Chat 语言模型
    一、确认本机显卡配置二、下载大模型国内可以从魔搭社区下载,下载地址:https://modelscope.cn/models/ZhipuAI/glm-4-9b-chat/files  三、运行官方代码 importtorchfromtransformersimportAutoModelForCausalLM,AutoTokenizerdevice="cuda"tokenizer=Aut......
  • 抖音矩阵智能剪辑系统源码,saas多平台多账号一站式管理,系统搭建流程
    ‘1.将MySQL升级至5.6版本,PHP更新至7.2版本,并使用Apache作为服务器。数据库应命名为“juzhen”。2.在Nginx环境下,实现伪静态的切换。3.将安装包解压至项目的根目录,并定位至`application/database.php`文件以更换数据库密码。4.保留阿里云的现有配置,根据提供的文档进行......
  • 日常中如何快速录屏
    日常中如何快速录屏1.原来是想找软件来录屏的,发现很多都是要收费的,这就。。。。。2.无意中发现qq录屏很方便和清晰3.登录QQ后面,调用的快捷键为ctrl+alt+a4.点击那个小圆点步是录屏了,录屏的大小你可以自己选择5.录屏完成后点保存就可以了......
  • Maven知识点概括(帮助你快速回顾Maven)
    一、Maven简介1、为什么学习Maven1.1、Maven是一个依赖管理工具随着我们使用越来越多的框架,或者框架封装程度越来越高,项目中使用的jar包也越来越多。项目中,一个模块里面用到上百个jar包是非常正常的。而如果使用Maven来引入这些jar包只需要配置三个“依赖”:<!--Nac......
  • 算法笔记:模拟过程(螺旋遍历矩阵)
    1模拟过程“模拟过程题”通常指的是那些要求编程者通过编写代码来“模拟”或重现某个过程、系统或规则的题目。这类题目往往不涉及复杂的数据结构或高级算法,而是侧重于对给定规则的精确执行和逻辑的清晰表达。其中螺旋遍历矩阵的题目就是一类典型的模拟过程题,需要精心设......
  • 从这几个优点了解快速自定义表单开发开源
    要实现提质增效的办公,需要应用什么软件平台?可以一起了解低代码技术平台、自定义表单开发开源。它们具有其他平台没有的优势特点,如可视化操作界面、更灵活、好操作、易维护等,因此,在竞争激烈的社会中,得到了各中大型企业的喜爱与支持。本文将罗列它的几个优势特点,让您清楚了解快速自......
  • 1. Docker快速起步
    Docker先安装Docker,再讲课没有Docker的日子里在以前的开发时代,开发人员把自己开发好的war交付给运维人员,运维人员为了把war部署到服务器上且保证能运行,就必须由运维人员在服务器上搭建好运行环境! 可这样带来的问题是,如果开发环境与部署环境不一致(比如版本),则会导致无法在服务器环......
  • Open3D 点云快速全局配准FGR算法(粗配准)
    目录一、概述1.1原理和步骤1.2关键技术和优势1.3应用场景二、代码实现2.1关键代码2.1.1.函数:execute_fast_global_registration2.1.2调用registration_fgr_based_on_feature_matching函数2.2完整代码三、实现效果3.1原始点云3.2粗配准后点云一、概述    ......
  • 短视频矩阵系统搭建教程,短视频矩阵怎么做,矩阵系统源码部署教程
    一、什么是矩阵系统这是一款智能助手系统,融合了账号授权管理、企业账户管理、AI素材库、视频剪辑创作、自动化回复响应、外部链接引流以及视频排名追踪等多重功能。简言之,这是一个助力企业提升短视频营销效果的智能助手平台。系统搭建获取\/:ywxs5787   备注来意二、矩......