zoukankan      html  css  js  c++  java
  • 线性代数初步

    1

    矩阵乘法规则:
    \(\begin{bmatrix}a_{1,1}&a_{1,2}&a_{1,3}\\a_{2,1}&a_{2,2}&a_{2,3}\end{bmatrix} \times \begin{bmatrix}b_{1,1}&b_{1,2}\\b_{2,1}&b_{2,2}\\b_{3,1}&b_{3,2}\end{bmatrix}=\begin{bmatrix}a_{1,1}b_{1,1}+a_{1,2}b_{2,1}+a_{1,3}b_{3,1}&a_{1,1}b_{1,2}+a_{1,2}b_{2,2}+a_{1,3}b_{3,2}\\a_{2,1}b_{1,1}+a_{2,2}b_{2,1}+a_{2,3}b_{3,1}&a_{2,1}b_{1,2}+a_{2,2}b_{2,2}+a_{2,3}b_{3,2}\end{bmatrix}\).
    以此类推,若 \(A \times B = C\) ,则 \(C\)\(m\) 行第 \(n\) 列的元素等于 \(A\)\(m\) 行的元素与 \(B\)\(n\) 列的元素对应乘积之和。

    struct mat
    {
    	int r,c;
    	int A[N][N];
    	mat()
    	{
    		memset(A,0,sizeof(A));
    	}
    };
    mat operator * (mat x,mat y)
    {
    	mat ans;
    	ans.r=x.r,ans.c=y.c;
    	for(int i=1;i<=ans.r;i++)
    	 	for(int j=1;j<=ans.c;j++)
    	 		for(int k=1;k<=x.c;k++)
    	 			ans.A[i][j]+=x.A[i][k]*y.A[k][j]%p,ans.A[i][j]%=p;
    	return ans;
    }
    

    若要算连续的矩阵乘法,可以用快速幂优化,写法与普通快速幂类似。
    根据矩阵乘法的计算方式,它可以用来处理某些类型的 dp 。
    尤其是当状态数较少但转移次数较多,且转移相同时,用矩阵快速幂优化可以达到很好的复杂度。

    2

    高斯消元

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #define db double
    using namespace std;
    const int N=110;
    const db eps=1e-9;
    int n;
    db a[N][N],ans[N];
    db ABS(db x)
    {
    	return x>eps?x:-x;
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n+1;j++) scanf("%lf",&a[i][j]);
    	for(int i=1;i<=n;i++)
    	{
    		int t=i;
    		for(int j=i+1;j<=n;j++)
    			if(ABS(a[j][i])-ABS(a[t][i])>eps) t=j;
    		swap(a[t],a[i]);
    		//找到第i个元素最大的行,换上来(减小精度误差) 
    		if(ABS(a[i][i])<eps)
    			puts("No Solution"),exit(0);
    		for(int j=i+1;j<=n+1;j++) a[i][j]/=a[i][i];
    		a[i][i]=1;
    		//把系数消成1,方便后面的操作 
    		for(int j=i+1;j<=n;j++)
    		{
    			for(int k=i+1;k<=n+1;k++)
    				a[j][k]-=a[i][k]*a[j][i];
    			a[j][i]=0;
    		}
    	}
    	for(int i=n;i>=1;i--)
    	{
    		ans[i]=a[i][n+1];
    		for(int j=i+1;j<=n;j++) ans[i]-=a[i][j]*ans[j];
    	}
    	for(int i=1;i<=n;i++) printf("%.2lf\n",ans[i]);
    	return 0;
    }
    

    3

    求行列式
    与高斯消元类似,但是不能直接使用实数(避免误差)。
    要用一行消去另一行时,用辗转相减的思想,每次消去最大的能消的整数倍,再把两行交换,以此类推。
    注意,交换时行列式变号。
    复杂度仍为 \(O(n^3)\)

    #include<iostream>
    #include<cstdio>
    #define int long long
    using namespace std;
    const int N=1010;
    int n,p;
    int a[N][N];
    signed main()
    {
    	scanf("%lld%lld",&n,&p);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			scanf("%lld",&a[i][j]),a[i][j]%=p;
    	int ans=1;
    	for(int i=1;i<n;i++)
    		for(int j=i+1;j<=n;j++)
    		{
    			while(a[i][i])
    			{
    				int t=a[j][i]/a[i][i];
    				for(int k=i;k<=n;k++)
    					a[j][k]-=a[i][k]*t%p,a[j][k]+=p,a[j][k]%=p;
    				swap(a[i],a[j]),ans=-ans;
    			}
    			swap(a[i],a[j]),ans=-ans;
    		}
    	for(int i=1;i<=n;i++) ans*=a[i][i],ans%=p;
    	printf("%lld",(ans+p)%p);
    	return 0;
    }
    

    4

    矩阵树定理。
    1
    无向无权图。
    \(A\) 为邻接矩阵,\(D\) 为度数矩阵(\(D_{i,i}\)\(i\) 点的度数,其它值为 0)。
    基尔霍夫矩阵为 \(K=A-D\)
    \(K'\)\(K\) 去掉第 \(k\) 行第 \(k\) 列后得到的矩阵,
    \(\det(K')\) 即为该图的生成树个数。
    (取任意 \(k\) 时得到的结果均相等)
    还可以处理有重边的情况。(若 \(i\)\(j\) 之间有 \(x\) 条边,则 \(A_{i,j}=A_{j,i}=x\)
    2
    有向图。
    若根为 \(r\) ,则 \(K'\)\(K\) 去掉第 \(r\) 行第 \(r\) 列后得到的矩阵。
    求内向生成树(由外向根)时, \(D_{i,i}=\sum \limits_{j=1}^n A_{i,j}\) .
    求外向生成树(由根向外)时, \(D_{i,i}=\sum \limits_{j=1}^n A_{j,i}\) .
    有重边时,同样可以处理。
    3
    有权图。
    把边权理解为重边,同样用上面的方法。
    此时求的就是所有生成树边权乘积的总和。

  • 相关阅读:
    [HAL]5.中断里调用HAL_Delay()进入死循环的原因
    【个人吐槽】C、Delphi、C#、java 摘抄
    【常用软件】木木的常用软件点评(2)------VC程序员常用工具篇
    【下位机软件】平均值滤波之鬼斧神工算法
    【vs2013】如何在VS的MFC中配置使用GDI+?
    【MFC】MFC改变对话框中静态文本的字体大小
    【MFC】VC界面绘制双缓存
    【MFC】如何在MFC创建的程序中更改主窗口的属性 与 父窗口 WS_CLIPCHILDREN 样式 对子窗口刷新的影响 与 窗体区域绘制问题WS_CLIPCHILDREN与WS_CLIPSIBLINGS
    Query的选择器中的通配符[id^='code']或[name^='code']
    获取checkbox数组 里面的值
  • 原文地址:https://www.cnblogs.com/zhs1/p/12763409.html
Copyright © 2011-2022 走看看