• 矩阵相关


    矩阵前置芝士

    矩阵:看成一个二维数组就好了.

    矩阵加法:

    本人认为没用
    条件:两个大小相同的矩阵
    对应位置相加,形成相同大小的矩阵.

    矩阵减法:

    本人认为没用
    条件:两个大小相同的矩阵

    对应位置相减,形成相同大小的矩阵.

    矩阵乘法:

    这个很重要
    条件:两个大小不完全一样的矩阵,必须保证矩阵(A(n*k)),矩阵B大小是(k*m)的,形成的矩阵C大小是(n*m)
    C矩阵中的x,y位置是A矩阵的X行,B矩阵的Y列相加.
    代码:

    for(int i = 1;i <= n;++ i) {
        for(int j = 1;j <= m;++ j) {
            for(int l = 1;l <= k;++ l) 
                C[i][j] += A[i][k] + B[k][j];
        }
    }
    

    性质:
    矩阵乘法具有结合律:
    (A*B*C = (A*B)*C = A*(B*C))

    矩阵快速幂

    ps:使用矩阵快速幂的时候一定要有模数.
    根据矩阵乘法具有结合律的性质,我们可以做矩阵的快速幂:
    例题---Luogu矩阵快速幂
    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define ll long long
    const int mod = 1e9 + 7;
    const int X = 110;
    
    ll n,k;
    
    struct Node {
        ll a[X][X];
        void clear() {
            memset(a,0,sizeof(a));
        }
    }res,ans;
    
    Node mul(Node a,Node b) {
        Node tmp;
        tmp.clear();
        for(int i = 1;i <= n;++ i) {
            for(int j = 1;j <= n;++ j) {
                for(int k = 1;k <= n;++ k) {
                    tmp.a[i][j] = (tmp.a[i][j] + (a.a[i][k] * b.a[k][j]) % mod ) % mod;
                } 
            } 
        }
        return tmp;
    }
    
    void fast_pow(ll k) {
        for(int i = 1;i <= n;++ i)
            ans.a[i][i] = 1;
        for(;k;k >>= 1,res = mul(res,res)) {
            if(k & 1)ans = mul(ans,res);
        }
        return ;
    }
    
    int main() {
        scanf("%lld%lld",&n,&k);
        for(int i = 1;i <= n; ++i ) {
            for(int j = 1;j <= n;++ j) {
                scanf("%lld",&res.a[i][j]);
            }
        }
        ans.clear();
        fast_pow(k);
        for(int i = 1;i <= n;++ i) {
            for(int j = 1;j <= n;++ j) {
                printf("%lld ",ans.a[i][j]);
            }
            printf("
    ");
        }
        return 0;
    }
    
    /*
    5
    5
    1 1 1 1 1
    1 0 0 1 0
    0 0 2 3 1
    0 0 0 1 0
    5 5 5 5 5
    */
    

    斐波那契数列

    我们可以通过矩阵快速幂来优化斐波那契数列斐波那契数列:$$f[n] = f[n - 1] + f[n - 2]$$
    放道例题:
    斐波那契数列---Luogu1962
    如何做:
    斐波那契数列的通项公式???
    显然不行,有精度问题.
    那我们来做矩阵快速幂
    题目中有f[1] = 1,f[2] = 1
    先构造矩阵(先不用管为什么这样构造):

    [ left{ egin{matrix} 1 & 1 \ end{matrix} ight} ag{1} ]

    表示

    [ left{ egin{matrix} 斐波那契数列第二项 & 斐波那契数列第一项 \ end{matrix} ight} ag{2} ]

    尝试往后推一项
    我们想要矩阵成这个样子

    [ left{ egin{matrix} 斐波那契数列第三项 & 斐波那契数列第二项 \ end{matrix} ight} ag{2} ]

    那我们要乘一个矩阵
    首先根据矩阵的定义,我们必须要构造一个(2*2)的矩阵
    首先给出构造好的矩阵:

    [ left{ egin{matrix} 1 & 1\ 1 & 0 \ end{matrix} ight} ag{3} ]

    模拟一下就好了.
    构造就是 根据生成的矩阵来构造中间的这个矩阵
    我们再回过头来看一下,为什么刚开始的矩阵是

    [ left{ egin{matrix} 1 & 1 \ end{matrix} ight} ag{1} ]

    因为f[3]要用到这两项啊.
    记住,矩阵快速幂中间的矩阵不可改变.
    这样我们就可以进行中间的矩阵(n -2)次幂的运算来获得一个矩阵啦,
    然后用刚开始的矩阵与这个矩阵相乘就得到第n项了.
    注意特判(n == 1,n == 2)的特殊情况

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #define ll long long
    const int maxN = 100 + 7;
    const ll mod = 1000000007;
    using namespace std;
    
    ll n,m,k;
    struct Marix{
        ll s[maxN][maxN];
        void clear() {
            memset(s,0,sizeof(s));
            return;
        }
    }ans,now,a;
    
    Marix work(Marix a,Marix b) {
        Marix c;
        c.clear();
        for(ll i = 1;i <= n;++ i) 
            for(ll j = 1;j <= n;++ j) 
                for(ll k = 1;k <= n;++ k) 
                    c.s[i][j] = ( c.s[i][j]  % mod+ ( a.s[i][k] * b.s[k][j] ) % mod ) % mod;
        return c;
    }
    
    void fast_pow() {
        ans.clear();
        for(ll i = 1;i <= n;++ i) {
            ans.s[i][i] = 1;
        }
        for(now = a;k;k >>= 1,now = work(now,now)) {
            if(k & 1) ans = work(ans,now);
        }
        Marix Q;
        Q.s[1][1] = 1;Q.s[1][2] = 1;
        ans = work(Q,ans);
        printf("%lld",ans.s[1][1]);
    }
    
    int main() {
        n = 2;
        scanf("%lld",&k);
        if(k == 1) {
        	printf("1");
        	return 0;
        }
        if(k == 2) {
            printf("1");
            return 0;
        }
        k -= 2;
        a.s[1][1] = 1;a.s[1][2] = 1;
        a.s[2][1] = 1;a.s[2][2] = 0;
        fast_pow();
        return 0;
    }
    

    矩阵递推相关

    给道例题:Luogu1939
    建议自己先构造一下:
    开始矩阵:

    [ left{ egin{matrix} 1 (第一项)& 1(第二项) & 1(第三项)\ end{matrix} ight} ag{1} ]

    中间的矩阵:

    [ left{ egin{matrix} 0 & 0 & 1\ 1 & 0 &0 \ 0 & 1 & 1\ end{matrix} ight} ag{1} ]

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #define ll long long
    const int maxN = 100 + 7;
    const int mod = 1e9 + 7;
    using namespace std;
    
    ll n,m,k;
    struct Marix{
        ll s[maxN][maxN];
        void clear() {
            memset(s,0,sizeof(s));
            return;
        }
    }ans,now,a;
    
    Marix work(Marix a,Marix b) {
        Marix c;
        c.clear();
        for(ll i = 1;i <= n;++ i) 
            for(ll j = 1;j <= n;++ j) 
                for(ll k = 1;k <= n;++ k) 
                    c.s[i][j] = ( c.s[i][j]  % mod+ ( a.s[i][k] * b.s[k][j] ) % mod ) % mod;
        return c;
    }
    
    void fast_pow() {
        ans.clear();
        for(ll i = 1;i <= n;++ i) {
            ans.s[i][i] = 1;
        }
        for(now = a;k;k >>= 1,now = work(now,now)) {
            if(k & 1) ans = work(ans,now);
        }
        Marix Q;
        Q.s[1][1] = 1;Q.s[1][2] = 1;Q.s[1][3] = 1;
        ans = work(Q,ans);
        printf("%lld
    ",ans.s[1][3]);
    }
    
    int main() {
        n = 3;
        int T;
        scanf("%d",&T);
        while(T --) {
            a.s[1][3] = a.s[2][1] = a.s[3][2] = a.s[3][3] = 1;
            scanf("%lld",&k);
            k -= 3;
            if(k <= 0) printf("1
    ");
            else fast_pow();
        }
        return 0;
    }
    

    矩阵快速幂优化DP

    设置状态f[i][j][k]表示i到j走k步的方案数
    设f[i][j][1] = 0/1表示i到j有没有路(0代表无路,1代表有)
    枚举中间点Q
    (f[i][j][k] = sum_{Q=1}^{n}f[i][Q][k - 1] * f[Q][j][1])
    HDU2157

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    const int maxN = 20 + 7;
    const int mod = 1000;
    using namespace std;
    
    struct Matrix
    {
    	int s[maxN][maxN];
    	Matrix() {memset(s,0,sizeof(s));}
    };
    
    int n,m;
    
    Matrix operator * (const Matrix &a,const Matrix &b) {
    	Matrix c;
    	for(int i = 1;i <= n;++ i) {
    		for(int j = 1;j <= n;++ j) {
    			for(int k = 1;k <= n;++ k) {
    				c.s[i][j] = (c.s[i][j] + a.s[i][k] * b.s[k][j] % mod) % mod;
    			}
    		}
    	}
    	return c;
    }
    
    Matrix fast_pow(Matrix a,int nn) {
    	Matrix ans;
    	for (int i = 1;i <= n; ++i)
    		ans.s[i][i] = 1;
    	for (; nn; nn >>= 1,a = a * a)
    	{
    		if(nn & 1) ans = ans * a;
    	}
    	return ans;
    }
    
    int main()
    {
    	while(~scanf("%d%d",&n,&m) && (n || m)) {
    		Matrix q;
    		for(int i = 1,u,v;i <= m;++ i) {
    			scanf("%d%d",&u,&v);
    			q.s[u + 1][v + 1] = 1;
    		}	
    		int T;
    		scanf("%d",&T);
    		int s,t,k;
    		while(T --) {
    			scanf("%d%d%d",&s,&t,&k);
    			Matrix b;
    			b = fast_pow(q,k);
    			printf("%d
    ", b.s[s + 1][t + 1]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    leetcode69
    leetcode204
    leetcode414
    leetcode532
    leetcode28
    leetcode155
    leetcode303
    leetcode190
    2018-7-21-win10-uwp-调用-Microsoft.Windows.Photos_8wekyb3d8bbwe-应用
    2018-7-21-win10-uwp-调用-Microsoft.Windows.Photos_8wekyb3d8bbwe-应用
  • 原文地址:https://www.cnblogs.com/tpgzy/p/9535017.html
Copyright © 2020-2023  润新知