zoukankan      html  css  js  c++  java
  • 矩阵快速幂(入门) 学习笔记hdu1005, hdu1575, hdu1757

    矩阵快速幂是基于普通的快速幂的一种扩展,如果不知道的快速幂的请参见http://www.cnblogs.com/Howe-Young/p/4097277.html。二进制这个东西太神奇了,好多优秀的算法都跟他有关系,这里所说的矩阵快速幂就是把原来普通快速幂的数换成了矩阵而已,只不过重载了一下运算符*就可以了,也就是矩阵的乘法,  当然也可以写成函数,标题中的这三个题都是关于矩阵快速幂的基础题。拿来练习练习熟悉矩阵快速幂,然后再做比较难点的,其实矩阵快速幂比较难的是构造矩阵。下面还是那题目直接说话:

    hdu1575:

    题目大意:求一个矩阵k此方之后主对角线上的元素之和对9973取模

    这个题是矩阵快速幂的裸题,直接用就行了。下面是代码

     1 #include<iostream>
     2 #include <string.h>
     3 #include <stdio.h>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 const int N = 11;
     8 const int mod = 9973;
     9 struct Matrix{
    10     int a[N][N];
    11 };
    12 int n;
    13 Matrix operator * (Matrix t1, Matrix t2)//重载运算符 *  
    14 {
    15     Matrix c;
    16     memset(c.a, 0, sizeof(c.a));
    17     //矩阵乘法 
    18     for (int k = 0; k < n; k++)
    19     {
    20         for (int i = 0; i < n; i++)
    21         {
    22             if (t1.a[i][k] <= 0)
    23                 continue;
    24             for (int j = 0; j < n; j++)
    25             {
    26                 if (t2.a[k][j] <= 0)
    27                     continue;
    28                 c.a[i][j] = (c.a[i][j] + t1.a[i][k] * t2.a[k][j]) % mod;
    29             }
    30         }
    31     }
    32     return c;
    33 }
    34 //重载^运算符 
    35 Matrix operator ^ (Matrix t, int k)
    36 {
    37     Matrix c;
    38     memset(c.a, 0, sizeof(c.a));
    39     //初始化矩阵c为单位阵 
    40     for (int i = 0; i < n; i++)
    41     {
    42         c.a[i][i] = 1;
    43     }
    44     //这里用到快速幂 
    45     for (; k; k >>= 1)
    46     {
    47         if (k & 1)
    48             c = c * t;
    49         t = t * t;
    50     }
    51     return c;
    52 }
    53 int main()
    54 {
    55     int T, k;
    56     cin >> T;
    57     while (T--)
    58     {
    59         cin >> n >> k;
    60         Matrix t1, t2;
    61         for (int i = 0; i < n; i++)
    62         {
    63             for (int j = 0; j < n; j++)
    64                 cin >> t1.a[i][j];
    65         }
    66         t2 = t1 ^ k;
    67         int res = 0;
    68         for (int i = 0; i < n; i++)
    69             res = (res + t2.a[i][i]) % mod;
    70         cout << res << endl;
    71     }
    72 
    73     return 0;
    74 }

    hdu1005:

    题目大意:

    f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.

    给你A, B和n让你求f(n)是多少

    这个题就需要稍微构造一下矩阵了

    这样的话要求F(n)的话,只需要对求出来F(n-1)就行了,对应的F(n-1)要求出F(n-2),所以题目给了F(1)和F(2),所以乘以他前面的系数矩阵就为【F(3), F(2)】T,再接着成系数矩阵就为【F(4),F(3)】T所以要求F(n)只需要对系数矩阵进行n-2次幂就行了,然后最后要求的结果就是矩阵的第一行第一列的结果,代码如下

     1 #include<iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 const int N = 2;
     8 const int mod = 7;
     9 struct Matrix
    10 {
    11     int mat[N][N];
    12 };
    13 //矩阵乘法(函数的形式) 
    14 Matrix Multi(Matrix a, Matrix b)
    15 {
    16     Matrix c;
    17     memset(c.mat, 0, sizeof(c.mat));
    18     for (int i = 0; i < N; i++)
    19     {
    20         for (int j = 0; j < N; j++)
    21         {
    22             for (int k = 0; k < N; k++)
    23                 c.mat[i][j] = (c.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % mod;
    24         }
    25     }
    26     return c;
    27 }
    28 //矩阵快速幂 (函数形式) 
    29 Matrix quickMatrixPower(Matrix a, int k)
    30 {
    31     Matrix t;
    32     memset(t.mat, 0, sizeof(t.mat));
    33     for (int i = 0; i < N; i++)
    34         t.mat[i][i] = 1;
    35     //快速幂 
    36     while (k)
    37     {
    38         if (k & 1)
    39             t = Multi(t, a);
    40         a = Multi(a, a);
    41         k >>= 1;
    42     }
    43     return t;
    44 }
    45 
    46 int main()
    47 {
    48     long long a, b, n;
    49     while (cin >> a >> b >> n && (a + b + n))
    50     {
    51         Matrix t;
    52         //初始化系数矩阵 
    53         t.mat[0][0] = a; 
    54         t.mat[0][1] = b;
    55         t.mat[1][0] = 1;
    56         t.mat[1][1] = 0;
    57         if (n >= 3)
    58         {
    59             t =  quickMatrixPower(t, n - 2);
    60             printf("%d
    ", (t.mat[0][0] + t.mat[0][1]) % mod);
    61         }
    62         else
    63         {
    64             printf("%lld
    ", n);
    65         }
    66     }
    67 
    68 
    69     return 0;
    70 }

    hdu1757

    题目大意:

    If x < 10 f(x) = x.
    If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10);
    And ai(0<=i<=9) can only be 0 or 1 .

    Now, I will give a0 ~ a9 and two positive integers k and m ,and could you help Lele to caculate f(k)%m.


    这个关键还是在于构造矩阵,因为给递推式了,所以矩阵还是比价好构造的,下图是构造的矩阵

    推到过程类似于1005,不再赘述,代码如下:

     1 #include<iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 const int ori[1][10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; 
     8 struct Matrix
     9 {
    10     int str[10][10];
    11 };
    12 int m;
    13 //矩阵乘法 
    14 Matrix operator * (Matrix a, Matrix b)
    15 {
    16     Matrix c;
    17     memset(c.str, 0, sizeof(c.str));
    18     for (int i = 0; i < 10; i++)
    19     {
    20         for (int j = 0; j < 10; j++)
    21         {
    22             for (int k = 0; k < 10; k++)
    23                 c.str[i][j] = (c.str[i][j] + a.str[i][k] * b.str[k][j]) % m;
    24        }
    25     }
    26     return c;
    27 }
    28 //矩阵快速幂 
    29 Matrix power (Matrix a, int k)
    30 {
    31     Matrix c;
    32     memset(c.str, 0, sizeof(c.str));
    33     for (int i = 0; i < 10; i++)
    34         c.str[i][i] = 1;
    35     while (k)
    36     {
    37         if (k & 1)
    38             c = c * a;
    39         a = a * a;
    40         k >>= 1;
    41     }
    42     return c;
    43 }
    44 //最后一步的矩阵乘法 
    45 int Multi(Matrix a)
    46 {
    47     Matrix c;
    48     memset(c.str, 0, sizeof(c.str));
    49     for (int i = 0; i < 1; i++)
    50     {
    51         for (int j = 0; j < 10; j++)
    52         {
    53             for (int k = 0; k < 10; k++)
    54             {
    55                 c.str[i][j] = (c.str[i][j] + ori[i][k] * a.str[k][j]) % m;
    56             }
    57         }
    58     }
    59     return c.str[0][0] % m;
    60 }
    61 int main()
    62 {
    63     int k;
    64     while (cin >> k >> m)
    65     {
    66         Matrix t;
    67         memset(t.str, 0, sizeof(t.str));
    68         for (int i = 0; i < 10; i++)
    69         {
    70             cin >> t.str[i][0];
    71             for (int j = 0; j < 10; j++)
    72                 if (i + 1 == j)
    73                     t.str[i][j] = 1;
    74         }
    75         if (k >= 10)
    76         {
    77             t = power(t, k - 9);
    78             printf("%d
    ", Multi(t));
    79         }
    80         else
    81         {
    82             printf("%d
    ", k);
    83         }
    84     }
    85 
    86     return 0;
    87 }
  • 相关阅读:
    vsftpd不支持目录软链接的解决办法
    SVN添加忽略目录
    Mysql 默认编码问题
    php-fpm 信号
    基于MAVEN使用IDEA创建dubbo入门项目图文教程
    taotao商城遇到的问题
    git push后出错
    Mybatis逆向工程自动生成代码(Ubuntu18.04-idea环境)
    git add.后回退 代码丢失
    对象的共享
  • 原文地址:https://www.cnblogs.com/Howe-Young/p/4212873.html
Copyright © 2011-2022 走看看