首页 > 其他分享 >矩阵乘法

矩阵乘法

时间:2023-08-06 20:57:26浏览次数:27  
标签:mat int 矩阵 leq Bmatrix 结合律 乘法

前言

目前感觉主要就是矩阵加速,一般·看到大一点的范围(加小一点的范围)可能会用到,是一个神奇的东西。
运用在广义矩阵和状态转移上面。
板子还是打得比较舒服的。
广义矩阵乘法具有结合律的条件是分别满足交换律和结合律,内层对外层满足分配律。

[NOI Online #1 入门组] 魔法

题目描述

C 国由 \(n\) 座城市与 \(m\) 条有向道路组成,城市与道路都从 \(1\) 开始编号,经过 \(i\) 号道路需要 \(t_i\) 的费用。

现在你要从 \(1\) 号城市出发去 \(n\) 号城市,你可以施展最多 \(k\) 次魔法,使得通过下一条道路时,需要的费用变为原来的相反数,即费用从 \(t_i\) 变为 \(-t_i\)。请你算一算,你至少要花费多少费用才能完成这次旅程。

注意:使用魔法只是改变一次的花费,而不改变一条道路自身的 \(t_i\);最终的费用可以为负,并且一个城市可以经过多次(包括 \(n\) 号城市)。

数据规模与约定

对于全部的测试点,保证:

  • \(1 \leq n \leq 100\),\(1 \leq m \leq 2500\),\(0 \leq k \leq 10^6\)。
  • \(1 \leq u_i, v_i \leq n\),\(1 \leq t_i \leq 10^9\)。
  • 给出的图无重边和自环,且至少存在一条能从 \(1\) 到达 \(n\) 的路径。

题解

比较神奇,考虑构造矩阵。首先我们有一个邻接矩阵,表示两点之间的最小花费,所以先做一遍Floyd。 \(O(n^{3})\)
然后暴力枚举每一条边变成负数之后的矩阵,存入新的矩阵,此时得到的就是k=1的情况。 \(O(mn^{2})\)
现在我们重新定义矩阵乘法,原来的加变成取min,原来的*变成+,其实就是松弛操作。
感性的东西来了,每对一个矩阵乘上k=1情况下的矩阵就相当于多施一次魔法,就是这样,其实也很形象。
这个矩阵仍然一样有结合律,证明如下:
+和min分别有交换律和结合律,+对min有分配律,得证。
所以就可以愉快地用矩阵加速了~。 \(O(\log_{k}n^{2})\)

code

#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
ll n,m,kk;
struct mat{
	ll a[105][105];
	mat(){memset(a,0x3f,sizeof(a));}
	void operator ~(){
		for(int i=1;i<=n;i++)
			a[i][i]=0;
	}
	mat operator *(const mat &T)const{
		mat res;
		ll r;
		for(int i=1;i<=n;i++)
			for(int k=1;k<=n;k++){
				r=a[i][k];
				for(int j=1;j<=n;j++)
					res.a[i][j]=min(res.a[i][j],r+T.a[k][j]);
			}
		return res;
	}
	mat operator ^(const ll &x)const{
		mat res,bas=*this;
		~res;
		for(ll b=x;b;b>>=1,bas=bas*bas)
			if(b&1)
				res=res*bas;
		return res;
	}
}ans,ba;
int main(){
	ll u[2505],v[2505],w[2505];
	scanf("%lld%lld%lld",&n,&m,&kk);
	~ans;~ba;
	for(int i=1;i<=m;i++){
		scanf("%lld%lld%lld",&u[i],&v[i],&w[i]);
		ans.a[u[i]][v[i]]=w[i];
	}
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				ans.a[i][j]=min(ans.a[i][j],ans.a[i][k]+ans.a[k][j]);
	if(kk==0){
		printf("%lld",ans.a[1][n]);
		return 0;
	}
	for(int k=1;k<=m;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				ba.a[i][j]=min(ba.a[i][j],ans.a[i][u[k]]+ans.a[v[k]][j]-w[k]);
	ans=ba^kk;
	printf("%lld",ans.a[1][n]);
}

GSS3 - Can you answer these queries III

题目描述

\(n\) 个数,\(q\) 次操作

操作0 x y把\(A_x\) 修改为\(y\)

操作1 l r询问区间\([l, r]\) 的最大子段和

题解

这里就是为了练矩阵才写矩阵的。
设 \(f(x)\) 为以当前数结尾的最大子段, \(g(x)\) 为前x个数的最大子段。
有 \(g(x)=max(f(x),g(x))\) , \(f(x)=max(a_x,a_x+f(x-1))\)。
定义矩阵乘法为先取加后取max
考虑矩阵

\[\begin{Bmatrix} f(i)\\ g(i)\\ 0 \end{Bmatrix} = \begin{Bmatrix} a_i & -\infty & a_i\\ a_i & 0 & a_i\\ -\infty & -\infty & 0 \end{Bmatrix} \begin{Bmatrix} f(i-1)\\ g(i-1)\\ 0 \end{Bmatrix} \]

然后把矩阵放到恰好需要结合律的线段树上。每次修改之后pushup上去就可以了。注意最后一次与 \(i=0\) 时作矩阵运算相当于直接取 \(max((2,1),(2,3))\)

code

#include<iostream>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=50005;
int n,v[N],q;
struct mat{
	int a[5][5];
	mat(){memset(a,0xcf,sizeof(a));}
	mat operator *(const mat &T)const{
		mat res;
		for(int i=1;i<=3;i++)
			for(int k=1;k<=3;k++){
				int r=a[i][k];
				for(int j=1;j<=3;j++)
					res.a[i][j]=max(res.a[i][j],r+T.a[k][j]);
			}
		return res;
	}
}t[N<<2],ba;
void init(mat &res,int x){
	res.a[1][1]=res.a[2][1]=res.a[1][3]=res.a[2][3]=x;
	res.a[1][2]=res.a[3][1]=res.a[3][2]=-inf;
	res.a[2][2]=res.a[3][3]=0;
}
void pushup(int p){
	t[p]=t[p<<1]*t[p<<1|1];
}
void biuld(int p=1,int cl=1,int cr=n){
	if(cl==cr){
		init(t[p],v[cl]);
		return ;
	} 
	int mid=cl+cr>>1;
	biuld(p<<1,cl,mid);
	biuld(p<<1|1,mid+1,cr);
	pushup(p);
}
void update(int d,int x,int p=1,int cl=1,int cr=n){
	if(cl==cr){
		init(t[p],x);
		return ;
	}
	int mid=cl+cr>>1;
	if(mid>=d)	update(d,x,p<<1,cl,mid);
	else	update(d,x,p<<1|1,mid+1,cr);
	pushup(p);
}
mat query(int l,int r,int p=1,int cl=1,int cr=n){
	if(l<=cl&&cr<=r)
		return t[p];
	int mid=cl+cr>>1;
	if(mid>=l&&mid<r)	return query(l,r,p<<1,cl,mid)*query(l,r,p<<1|1,mid+1,cr);
	else if(mid>=l)	return query(l,r,p<<1,cl,mid);
	else if(mid<r)	return query(l,r,p<<1|1,mid+1,cr);
}
int main(){
	int a,b,c;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&v[i]);
	biuld();
	scanf("%d",&q);
	while(q--){
		scanf("%d%d%d",&a,&b,&c);
		if(a==0)
			update(b,c);
		else{
			mat tmp=query(b,c);
			printf("%d\n",max(tmp.a[2][1],tmp.a[2][3]));
		}
	}
}

标签:mat,int,矩阵,leq,Bmatrix,结合律,乘法
From: https://www.cnblogs.com/whz-lld/p/17607260.html

相关文章

  • 矩阵乘法 笔记
    众所周知,数是可以进行加减乘除的,那矩阵为啥不可以呢?假设现在我们有两个矩阵\(A\)和\(B\),矩阵大小分别为\(n\timesm\)和\(x\timesy\),矩阵元素对\(mod\)取模。基本运算矩阵加法令\(A+B=C\)。要求:\(n=x\)并且\(m=y\)。其实很简单,就是一一对应着加就行,即......
  • Co-occurrence Network:相关系数矩阵的阈值
    "abs(occor.r)<0.7"这部分代码是对相关系数矩阵进行阈值处理的一部分。这里的"0.7"是一个阈值,用来筛选相关性较强的微生物对。具体来说,对于相关系数矩阵中的每个元素,如果其绝对值小于0.7,则将其设置为0。相关系数范围在-1到1之间,绝对值越接近1表示相关性越强,绝对值越接近0表......
  • 线性方程组数学原理、矩阵原理及矩阵变换本质、机器学习模型参数求解相关原理讨论
    线性方程组数学原理、矩阵原理及矩阵变换本质、机器学习模型参数求解相关原理讨论1.线性方程组0x1:无处不在的线性方程组日常生活或生产实际中经常需要求一些量,用未知数x1,x2,....,xn表示这些量,根据问题的实际情况列出方程组,而最常见的就是线性方程组(当然并不......
  • 矩阵求导与矩阵微分
    简介下面的系列文章来自知乎用户iterator,是我见过最好的矩阵求导教程,没有之一!强烈推荐去看作者原文!矩阵求导的本质与分子布局、分母布局的本质(矩阵求导——本质篇)-知乎矩阵求导公式的数学推导(矩阵求导——基础篇)-知乎矩阵求导公式的数学推导(矩阵求导——进阶篇)-知......
  • LeetCode 热题 100 之 54. 螺旋矩阵
    题目给你一个m行n列的矩阵matrix,请按照顺时针螺旋顺序,返回矩阵中的所有元素。示例1:输入:matrix=[[1,2,3],[4,5,6],[7,8,9]]输出:[1,2,3,6,9,8,7,4,5]示例2:输入:matrix=[[1,2,3,4],[5,6,7,8],[9,10,11,12]]输出:[1,2,3,4,8,12,11,10,9,5,6,7]提示:m==matrix.......
  • doubly block toeplitz matrix 在加速矩阵差卷积上的应用
    文档链接CNN的卷积是执行了\(w'_{i,j}=\sum\limits_{x,y}w_{i+x,j+y}\timesC_{x,y}\),有人认为每次平移卷积核,运算量很大,又是乘法又是加法。现在我们吧\(w_{x,y}\)展开形成一个\([n\timesm,1]\)的向量\(V\),然后构造一个大小为\([(n+1)\times(m+1),n\timesm]\)矩阵......
  • 矩阵计算(导数)
    1标量的导数2亚导数比如说\(y=|x|\)这个函数在x=0的时候时不可导的。当x>0,其到导数为1,x<0,其导数为-1,所以在x=0的这个地方的亚导数就是可以是[-1,1]中的一个数梯度这里主要搞得清楚他的形状∂y/∂x当y是标量,x是向量的时候:它的结果是个横着的矩阵求导向量化的优点......
  • 【线性代数】求逆矩阵的方法
    1.用公式,将求逆转化为求伴随矩阵和行列式2.根据性质,可逆矩阵一定可以写成一系列初等矩阵乘积的形式3.根据可逆的定义,找到能使AB=E成立的矩阵B(不过这个方法一般适合用于一些简单的或者形式特殊的矩阵。4.通过分块矩阵求逆的性质,将大矩阵的求逆转换为小矩阵求逆。......
  • 高维矩阵乘法学习总结
    参考:【深度学习中的数学】高维矩阵乘法规则【全面理解多维矩阵运算】多维(三维四维)矩阵向量运算-超强可视化baseKnowlegde:高维矩阵相当于二维矩阵的顺序堆叠相同维度数目举例:Ashape[a,b,c,d],Bshape[e,f,g,h]For高维(除第一维和第二维之外)长度相同:(eg.\(a......
  • 剑指 Offer 29. 顺时针打印矩阵(简单)
    题目://不可以用代码随想录里螺旋矩阵的思路classSolution{public:vector<int>spiralOrder(vector<vector<int>>&matrix){vector<int>result;if(matrix.empty())returnresult;intrl=0,rh=matrix.size()-1;......