算法与竞赛(第14章) - 矩阵基本运算

第1关:运用矩阵求解A+rX=B

任务描述

本关任务:给定两个相同大小的矩阵A和矩阵B,以及一个系数r,运用矩阵的基本运算法则编写一个程序计算A+rX=B的解:矩阵X。

例如等式:

可以求得矩阵X为:

相关知识

为了完成本关任务,你需要掌握:1.矩阵的加法与减法,2.矩阵与数的乘法。

矩阵的加法与减法

矩阵定义:由m×n个数按照m行n列的形式而排成的数表称之为m行n列的矩阵,简称m×n矩阵。用符号记作为A=(a

ij

),其中i=1,2..m,j=1,2..n:

这m×n个数称为矩阵A的元素,简称为元。矩阵A的第i行第j列元素用a

ij

表示,称为矩阵A的(i,j)元。

矩阵的加法和减法运算定义为逐个元素进行加法或减法,因此两个矩阵的行数、列数分别相等。给定矩阵A和矩阵B,如下:

它们的加减法运算为A±B:

简而言之,两个矩阵的加减就是它们相同位置的元素的加减。特别的,矩阵加法运算满足以下运算性质:

交换律:A+B=B+A

结合律:(A+B)+C=A+(B+C)

矩阵与数的乘法

设矩阵A是一个m×n的矩阵,r是一个实数,则数r与矩阵A相乘的结果为一个相同大小的矩阵,记为rA:

简单来说,数r乘矩阵A,就是将数r乘矩阵A中的每一个元素。特别的,数乘也满足一些运算性质:

结合律:(r

1

×r

2

)×A=r

1

×(r

2

×A)

分配律:r×(A+B)=r×A+r×B

编程要求

本关的编程任务是补全右侧代码片段operator +和operator -中Begin至End中间的代码,具体要求如下:

在operator +中,运用矩阵的基本加法运算法则,计算两个矩阵(结构体内部矩阵指针this和参数矩阵B)的加法,并返回加法运算后的结果矩阵。

在operator -中,运用矩阵的基本减法运算法则,计算两个矩阵的减法,并返回减法运算后的结果矩阵。

在operator *中,运用矩阵的基本数乘运算法则,计算矩阵与数的乘法,并返回数乘运算后的结果矩阵。

测试说明

平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。

以下是平台的测试样例:

测试输入:

3 3

2

3 -1 2

1 5 7

2 4 5

7 5 -2

5 1 9

4 2 1

预期输出:

2.00 3.00 -2.00

2.00 -2.00 1.00

1.00 -1.00 -2.00

输入格式:

第1行:矩阵A和矩阵B的大小(m,n)

第2行:系数r

接下来m行(每行n个数):矩阵A

接下来m行(每行n个数):矩阵B

输出格式:

m行n列的矩阵

开始你的任务吧,祝你成功!

//
//  main.cpp
//  step1
//
//  Created by ljpc on 2018/11/24.
//  Copyright © 2018年 ljpc. All rights reserved.
//

#include <iostream>
#include <algorithm>

using namespace std;

struct Matrix{
    int m, n;
    double **val;
    Matrix(){}
    Matrix(int m_, int n_){
        m = m_;
        n = n_;
        this->val = (double**)malloc(sizeof(double*)*m);
        for(int i=0;i<m;i++){
            this->val[i] = (double*)malloc(sizeof(double)*n);
        }
    }
    void in(){
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                scanf("%lf", &this->val[i][j]);
            }
        }
    }
    void out(){
        for(int i=0;i<m;i++){
            printf("%.2lf", this->val[i][0]);
            for(int j=1;j<n;j++){
                printf(" %.2lf", this->val[i][j]);
            }
            printf("\n");
        }
    }
    Matrix operator + (const Matrix B)const{
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
       Matrix result(m, n);  // 创建一个新矩阵来存储结果

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                result.val[i][j] = this->val[i][j] + B.val[i][j];  // 将对应位置的元素相加
            }
        }

        return result;  // 返回结果矩阵
 
        /********* End *********/
        
    }
    Matrix operator - (const Matrix B)const{
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
       Matrix result(m, n);  // 创建一个新矩阵来存储结果

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                result.val[i][j] = this->val[i][j] - B.val[i][j];  // 将对应位置的元素相减
            }
        }

        return result;  // 返回结果矩阵
 
        /********* End *********/
    }
    Matrix operator * (const double r)const{
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
       Matrix result(m, n);  // 创建一个新矩阵来存储结果

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                result.val[i][j] = this->val[i][j] * r;  // 将每个元素乘以给定的数
            }
        }

        return result;  // 返回结果矩阵
 
        /********* End *********/
    }

};

int main(int argc, const char * argv[]) {
    
    int m, n;
    double r;
    scanf("%d %d", &m, &n);
    scanf("%lf", &r);
    
    Matrix A(m,n);
    A.in();
    Matrix B(m,n);
    B.in();
    
    Matrix C(m,n);
    C = (B-A)*0.5;
    C.out();
    
    return 0;
}

第2关:矩阵乘法的运用

任务描述

本关任务:学习矩阵乘法的运算法则,编程实现给定的两个矩阵A和B的乘法运算。

例如矩阵A和B分别为:

它们的乘法运算结果为矩阵C=A×B:

相关知识

为了完成本关任务,你需要掌握:1.矩阵的乘法。

矩阵的乘法

矩阵乘法是矩阵基础运算中最为复杂的,也是最为重要的运算。两个矩阵相乘,首先需要满足的相乘的基本条件:对于矩阵A和矩阵B,只有当矩阵A的列数等于矩阵B的行数时,矩阵A才能乘以矩阵B,即A×B,否则它们不能进行乘法运算。因此,做矩阵乘法运算的两个矩阵也不能随便跟换位置。

运算定义:设矩阵A为m×p阶的矩阵,矩阵B为p×n阶的矩阵:

则矩阵A和矩阵B的乘积记做AB或A×B,结果为矩阵C:

其中每一项c

ij

表达式如下:

由此可以看出,矩阵A和矩阵B相乘后得到的矩阵C的行数与左矩阵A的行数相同,列数与右矩阵B的列数相同,即C=(c

ij

)

m×n

。矩阵C中第i行第j列的元素由矩阵A的第i行的元素与矩阵B的第j列的元素对应相乘,然后再取乘积之和。

虽然根据矩阵乘法运算的定义可以得出矩阵乘法不满足交换律的性质,但是矩阵乘法仍然有很多实用的性质,比如:

结合律:对于矩阵A、B、C,若A的列数等于B的行数,B的列数又等于C的行数,则有以下等式成立:

(AB)C=A(BC)

α(AB)=(αA)B=A(αB)

分配律:(A+B)C=AC+BC,C(A+B)=CA+CB。

编程要求

本关的编程任务是补全右侧代码片段operator *中Begin至End中间的代码,具体要求如下:

在operator *中,根据矩阵的乘法运算法则,在矩阵结构体中,实现矩阵乘法的重载函数:计算两个矩阵(结构体内部矩阵指针this和参数矩阵B)的乘法,并返回乘法运算后的结果矩阵。

测试说明

平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。

以下是平台的测试样例:

测试输入:

2 2

1 2

1 -1

2 3

1 2 -3

-1 1 2

预期输出:

-1 4 1

2 1 -5

输入格式:

第1行:矩阵A的m和p

接下来m行,每行p列(矩阵A)

第1+m行:矩阵B的p和n

接下来p行,每行n列(矩阵B)

输出格式:

乘法运算后的矩阵C

开始你的任务吧,祝你成功!

//
//  main.cpp
//  step2
//
//  Created by ljpc on 2018/11/24.
//  Copyright © 2018年 ljpc. All rights reserved.
//

#include <iostream>
#include <algorithm>

using namespace std;

struct Matrix{
    int m, n;
    int **val;
    Matrix(){}
    Matrix(int m_, int n_){
        m = m_;
        n = n_;
        this->val = (int**)malloc(sizeof(int*)*m);
        for(int i=0;i<m;i++){
            this->val[i] = (int*)malloc(sizeof(int)*n);
        }
    }
    void in(){
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                scanf("%d", &this->val[i][j]);
            }
        }
    }
    void out(){
        for(int i=0;i<m;i++){
            printf("%d", this->val[i][0]);
            for(int j=1;j<n;j++){
                printf(" %d", this->val[i][j]);
            }
            printf("\n");
        }
    }
    Matrix operator * (const Matrix B)const{
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
       Matrix result(m, B.n);
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < B.n; j++) {
                result.val[i][j] = 0;
                for (int k = 0; k < n; k++) {
                    result.val[i][j] += this->val[i][k] * B.val[k][j];
                }
            }
        }
        return result;
 
        /********* End *********/
        
    }
    
};

int main(int argc, const char * argv[]) {
    
    int m1, n1;
    scanf("%d %d", &m1, &n1);
    Matrix A(m1,n1);
    A.in();
    
    int m2, n2;
    scanf("%d %d", &m2, &n2);
    Matrix B(m2,n2);
    B.in();
    
    Matrix C(m1,n2);
    C = A*B;
    C.out();
    
    return 0;
}

第3关:矩阵转置的运用

任务描述

本关任务:学习矩阵转置的运算法则,编程实现给定的矩阵A的转置运算。

例如给定的矩阵A为:

它的转置运算结果矩阵T为:

相关知识

为了完成本关任务,你需要掌握:1.矩阵的转置。

矩阵的转置

转置运算定义:将矩阵A的行换成同序号的列(行与列进行交换)所得到的新矩阵称为矩阵A的转置矩阵,记作A

T

或$$A^{`}$$。

设矩阵A为m×n阶矩阵:

则A的转置矩阵A

T

为n×m阶矩阵:

同时,根据矩阵转置运算的定义我们可以得出如下性质:

(A

T

)

T

=A,矩阵转置的转置等于自身;

(A+B)

T

=A

T

+B

T

,两个矩阵的和的转置等于各个矩阵转置之后的和;

(AB)

T

=B

T

A

T

,两个矩阵的乘积的转置等于相反顺序的各个矩阵的转置之后的乘;

(αA)

T

=αA

T

,数与矩阵乘法后的转置矩阵等于数乘以转置矩阵的矩阵。

编程要求

本关的编程任务是补全右侧代码片段Transpose中Begin至End中间的代码,具体要求如下:

在Transpose中,根据矩阵的转置运算法则,在矩阵结构体中,实现矩阵的转置,并返回转置运算后的结果矩阵。

测试说明

平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。

以下是平台的测试样例:

测试输入:

2 4

1 0 3 -1

2 1 0 2

预期输出:

1 2

0 1

3 0

-1 2

输入格式:

第1行:矩阵A的m和n

接下来m行,每行n列(矩阵A)

输出格式:

转置运算后的矩阵T

开始你的任务吧,祝你成功!

//
//  main.cpp
//  step3
//
//  Created by ljpc on 2018/11/24.
//  Copyright © 2018年 ljpc. All rights reserved.
//


#include <iostream>
#include <algorithm>

using namespace std;

struct Matrix{
    int m, n;
    int **val;
    Matrix(){}
    Matrix(int m_, int n_){
        m = m_;
        n = n_;
        this->val = (int**)malloc(sizeof(int*)*m);
        for(int i=0;i<m;i++){
            this->val[i] = (int*)malloc(sizeof(int)*n);
        }
    }
    void in(){
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                scanf("%d", &this->val[i][j]);
            }
        }
    }
    void out(){
        for(int i=0;i<m;i++){
            printf("%d", this->val[i][0]);
            for(int j=1;j<n;j++){
                printf(" %d", this->val[i][j]);
            }
            printf("\n");
        }
    }
    Matrix Transpose ()const{
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
       Matrix result(n, m); // 创建一个新的矩阵来存储转置结果
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                result.val[j][i] = this->val[i][j]; // 将原矩阵的行变成新矩阵的列
            }
        }
        return result;
 
        /********* End *********/
        
    }
    
};

int main(int argc, const char * argv[]) {
    
    int m, n;
    scanf("%d %d", &m, &n);
    Matrix A(m,n);
    A.in();
    
    
    Matrix C(n,m);
    C = A.Transpose();
    C.out();
    
    return 0;
}
相关推荐
双子座断点几秒前
QT 机器视觉 (3. 虚拟相机SDK、测试工具)
qt·1024程序员节
20岁30年经验的码农13 分钟前
爬虫基础
1024程序员节
licy__33 分钟前
计算机网络IP地址分类,子网掩码,子网划分复习资料
1024程序员节
Chris-zz1 小时前
Linux:磁盘深潜:探索文件系统、连接之道与库的奥秘
linux·网络·c++·1024程序员节
JasonYin~1 小时前
《探索 HarmonyOS NEXT(5.0):开启构建模块化项目架构奇幻之旅 —— 模块化基础篇》
1024程序员节
TeYiToKu1 小时前
笔记整理—linux驱动开发部分(1)驱动梗概
linux·c语言·arm开发·驱动开发·嵌入式硬件
Teamol20202 小时前
求助帖:ubuntu22.10 auto install user-data配置了为何还需要选择语言键盘(如何全自动)
linux·ubuntu·1024程序员节
DdddJMs__1352 小时前
C语言 | Leetcode C语言题解之第517题超级洗衣机
c语言·leetcode·题解
尘佑不尘2 小时前
shodan5,参数使用,批量查找Mongodb未授权登录,jenkins批量挖掘
数据库·笔记·mongodb·web安全·jenkins·1024程序员节