算法与竞赛(第15章) - 矩阵高级运算

第1关:矩阵(方阵)行列式

任务描述

本关任务:掌握特殊矩阵(方阵)的行列式的概念,编程实现n阶行列式的值。例如2阶方阵:,它的行列式的值为:Det(A)=1×4−2×3=−2。

相关知识

为了完成本关任务,你需要掌握:1.行列式的定义。

行列式的定义

当一个矩阵的行数和列数相等时,称这个矩阵为方阵,若行数为1,则称之为一阶方阵,若行数为2,则称之为二阶方阵,以此类推,若行数为n,则称之为n阶方阵。

一阶方阵只有一个元素,它的行列式的值就是本身。记方阵为A,行列式的值用D表示,则D=Det(A)。

二阶方阵每行每列都是两个元素,设二阶方阵,那么二阶行列式记为,并称a

ij

(i,j=1,2)为行列式的元素。二阶行列式即是由四个元素排列成两行两列,并按一定规则得到的一个值。例如:

三阶行列式则是形如的数据块,即由9个元素排成的三行三列,并按一定规则得到的一个值,记三阶行列式为D,则。例如:

n阶行列式为由n

2

个元素a

ij

(i,j=1,2,..,n)排成n行n列,并按一定规则得到的一个值,记为:,其值为n!项之和:,其中是将序列的元素次序交换k次所得到的一个序列,k即为交换后的序列相对原序列的逆序数(在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数)。

编程要求

本关的编程任务是补全右侧代码片段Determinant_1、Determinant_2、Determinant_3、Inverse_Number和Determinant_n中Begin至End中间的代码,具体要求如下:

在Determinant_1中,计算一阶方阵的行列式,并返回行列式的值。

在Determinant_2中,计算二阶方阵的行列式,并返回行列式的值。

在Determinant_3中,计算三阶方阵的行列式,并返回行列式的值。

在Inverse_Number中,计算由n个数组成的序列(整型数组a)的逆序数,并返回逆序数值。

在Determinant_n中,计算n阶方阵的行列式,并返回行列式的值。

测试说明

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

以下是平台的测试样例:

测试输入:

2

1 2

3 4

预期输出:

-2

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

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

#include <iostream>
#include <algorithm>

using namespace std;
int det(int n, int** mat)
{
    int mov = 0;
    int flag;
    int sum = 0;
    if (n == 1) return mat[0][0];
    int** b = new int* [n - 1];
    for (int z = 0; z < n - 1; ++z)
        b[z] = new int[n - 1];
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < n - 1; ++j) {
            mov = i > j ? 0 : 1;
            for (int k = 0; k < n - 1; ++k)
                b[j][k] = mat[j + mov][k + 1];
        }
        if (i % 2 == 0) flag = 1;
        else flag = -1;
        sum += flag * mat[i][0] * det(n - 1, b);
    }
    delete[] b;
    return sum;
}
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");
        }
    }
    int Determinant_1 (){
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
        return val[0][0];
        /********* End *********/
    }
    int Determinant_2 (){
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
        return (val[0][0] * val[1][1] - val[0][1] * val[1][0]);
        /********* End *********/
    }
    int Determinant_3 (){
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
        int left = val[0][0] * val[1][1] * val[2][2] + val[0][1] * val[1][2] * val[2][0] + val[1][0] * val[2][1] * val[0][2];
        int right = val[2][0] * val[1][1] * val[0][2] + val[1][0] * val[0][1] * val[2][2] + val[2][1] * val[1][2] * val[0][0];
        return left - right;
        /********* End *********/
    }
    int Inverse_Number(int n, int arr[]){
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
        int count = 0;
        for (int i = 0; i < n - 1; i++) {
            for (int j = i + 1; j < n; j++) {
                if (arr[i] > arr[j]) {
                    count++;
                    break;
                }
            }
        }
        return count;
        /********* End *********/
    }
    int Determinant_n (){
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
        int res = det(this->n, this->val);
        return res;
        /********* End *********/
    }
    
    int Determinant (){
        if(this->n==1){
            return Determinant_1();
        }else if(this->n==2){
            return Determinant_2();
        }else if(this->n==3){
            return Determinant_3();
        }else {
            return Determinant_n();
        }
    }
    
};

int main(int argc, const char * argv[]) {
    
    int n;
    scanf("%d", &n);
    Matrix A(n,n);
    A.in();
    
    int det = A.Determinant();
    printf("Det(A)=%d\n", det);
    
    return 0;
}

第2关:矩阵逆运算

任务描述

本关任务:掌握特殊矩阵(方阵)的逆的概念,编程实现n阶矩阵的逆矩阵。

例如:矩阵,其逆矩阵。

相关知识

为了完成本关任务,你需要掌握:1.单位矩阵的定义,2.代数余子式,3.伴随矩阵,4.逆矩阵的定义。

单位矩阵的定义

单位矩阵的定义:从左上角到右下角的对角线(称为主对角线)上的元素均为1,除此以外全都为0。

代数余子式

设矩阵A=(a

ij

),将矩阵A的元素aij所在的第i行第j列去掉后,余下的(n−1)

2

项按原来的排列顺序组合成的(n−1)阶矩阵所确定的行列式称为元素aij的余子式,即为Mij,称Aij=(−1)

i+j

Mij为元素aij的代数余子式。

伴随矩阵

矩阵A=(a

ij

)

n×n

的各元素的代数余子式Aij所构成的如下矩阵A

该矩阵A

称为矩阵A的伴随矩阵。

逆矩阵的定义

给定整数a和b,且b

=0,则a除以b可写为:

b

a

=ab

−1

,在等式中,称b

−1

=

b

1

为b的逆元,显然有b

−1

b=bb

−1

=1。

对于矩阵来说,矩阵的除法可以归结为乘法运算。对于n阶矩阵(方阵)A,若存在n阶矩阵B,使得:AB=BA=I,其中I为单位矩阵,则称B为A的逆矩阵,并称A为可逆矩阵或可逆方阵,记A的逆矩阵为A

−1

特别的,由行列式的乘法可得等式∣A∣∣A

−1

∣=∣AA

−1

∣=∣I∣=1,因此∣A∣

=0。可见,要判断一个矩阵是否有逆矩阵存在,只需要判断该矩阵是否为非奇异矩阵(行列式的值不等于零)。

设矩阵A为n阶非奇异矩阵,则A有唯一的一个逆矩阵A

−1

其中,A

为A的伴随矩阵,为行列式∣A∣中元素的代数余子式。

编程要求

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

在Cofactor中,根据矩阵余子式的定义,计算去掉矩阵第x行第y列元素后的余子式,并返回该余子式的值。

在Adjugate_Matrix中,根据伴随矩阵的定义,借助Cofactor函数计算矩阵(∗this)的伴随矩阵,并返回该伴随矩阵。

在Inverse_Matrix中,根据逆矩阵的定义,通过计算矩阵的行列式的值及其伴随矩阵,求得矩阵(∗this)的逆矩阵并返回。

在Identity_Matrix中,根据单位矩阵的定义,判断矩阵(∗this)是否为单位矩阵,若是,返回true,否则,返回false。

测试说明

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

以下是平台的测试样例:

测试输入:

2

1 2

3 4

预期输出:

-2.0000 1.0000

1.5000 -0.5000

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

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

#include <iostream>
#include <algorithm>

using namespace std;

#define eps 1e-8
inline int sig(double x){return (x>eps)-(x<-eps); }

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("%.4lf", this->val[i][0]);
            for(int j=1;j<n;j++){
                printf(" %.4lf", this->val[i][j]);
            }
            printf("\n");
        }
    }
    Matrix operator * (const double r)const{
        int m_ = this->m;
        int n_ = this->n;
        Matrix A = *this;
        Matrix M(m_, n_);
        for(int i=0;i<m_;i++){
            for(int j=0;j<n_;j++){
                M.val[i][j] = A.val[i][j] * r;
            }
        }
        return M;
    }
    Matrix operator * (const Matrix B)const{
        Matrix A = *this;
        Matrix M(A.m, B.n);
        if(A.n!=B.m){
            printf("error\n");
        }
        for(int i=0;i<A.m;i++){
            for(int j=0;j<B.n;j++){
                double sum = 0;
                for(int k=0;k<A.n;k++){
                    sum += A.val[i][k] * B.val[k][j];
                }
                M.val[i][j] = sum;
            }
        }
        return M;
    }
    int Inverse_Number (int n, int arr[]) {
        int num = 0;
        for(int i=0;i<n;i++){
            for(int j=0;j<i;j++){
                if(arr[j]>arr[i]){
                    num++;
                }
            }
        }
        return num;
    }
    double Determinant () {
        Matrix D = *this;
        double det = 0;
        int *arr;
        arr = (int*)malloc(sizeof(int)*D.n);
        for(int i=0;i<D.n;i++){
            arr[i] = i;
        }
        do{
            int inv = Inverse_Number(D.n, arr);
            double tmp = (inv%2==0)?1:-1;
            for(int i=0;i<D.n;i++){
                tmp *= D.val[i][arr[i]];
            }
            det += tmp;
        }while(next_permutation(arr, arr+D.n));
        return det;
    }
    
    
    double Cofactor (int x, int y) {
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
        Matrix C = Matrix(this->n-1,this->n-1);
        for(int i=0;i<x;i++){
            for(int j=0;j<y;j++){
                C.val[i][j] = this->val[i][j];
            }
        }
        for(int i=0;i<x;i++){
            for(int j=y+1;j<this->n;j++){
                C.val[i][j-1] = this->val[i][j];
            }
        }
        for(int i=x+1;i<this->n;i++){
            for(int j=0;j<y;j++){
                C.val[i-1][j] = this->val[i][j];
            }
        }
        for(int i=x+1;i<this->n;i++){
            for(int j=y+1;j<this->n;j++){
                C.val[i-1][j-1] = this->val[i][j];
            }
        }
        double det_c = C.Determinant();
        return det_c;

        /********* End *********/
    }
    
    Matrix Adjugate_Matrix () {
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
         Matrix A = Matrix(this->n, this->n);
        for(int i=0;i<A.n;i++){
            for(int j=0;j<A.n;j++){
                int flag = ((i+j)%2==0)?1:-1;
                int M_ij = Cofactor(i, j);
                A.val[j][i] = flag * M_ij;
            }
        }
        return A;

        /********* End *********/
    }
    
    Matrix Inverse_Matrix (){
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
        double det = Determinant();
        if(det == 0){
            printf("error\n");
            return Matrix();
        }
        Matrix I = Matrix(this->n, this->n);
        Matrix A = Matrix(this->n, this->n);
        A = Adjugate_Matrix();
        I = A * (1./det);
        return I;

        /********* End *********/
    }
    
    bool Identity_Matrix() {
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
        for(int i=0;i<this->n;i++){
            for(int j=0;j<this->n;j++){
                if(i==j){
                    if(sig(this->val[i][j]-1)!=0){
                        return false;
                    }
                }else {
                    if(sig(this->val[i][j]-0)!=0){
                        return false;
                    }
                }
            }
        }
        return true;

        /********* End *********/
    }
    
};

int main(int argc, const char * argv[]) {
    
    int n;
    scanf("%d", &n);
    Matrix A(n,n);
    A.in();
    
    Matrix I(n,n);
    I = A.Inverse_Matrix();
    I.out();
    
    Matrix E1(n,n);
    Matrix E2(n,n);
    E1 = A*I;
    E2 = I*A;
    if(E1.Identity_Matrix()==false){
        printf("A*I error\n");
        E1.out();
    }
    if(E2.Identity_Matrix()==false){
        printf("I*A error\n");
        E2.out();
    }
    
    return 0;
}

第3关:矩阵初等变换

任务描述

本关任务:掌握矩阵的初等变换的基本操作,并通过矩阵初等变换计算n阶矩阵的逆矩阵。

相关知识

为了完成本关任务,你需要掌握:1.初等变换的定义,2.初等行变换求逆矩阵,3.初等列变换求逆矩阵。

初等变换的定义

对一个矩阵施行下面的变换称之为矩阵的初等变换:

对换矩阵的某两行或两列;

任一非零常数乘以矩阵的某行或某列;

常数乘以矩阵的某行(列)元素加到另一行(列)的对应元素上。

根据施行在行或是列上,初等变换可分为初等行变换和初等列变换。

初等行变换求逆矩阵

通过初等行变换可以将形如的矩阵转换为形如的矩阵。具体步骤如下:

初始i=1,将第i行的所有元素a[i,j],j∈[i,n]除以a[i,i]。

枚举第i+1行至第m行,将第k∈[i+1,m]行的元素进行初等变换:

flag=a[k,i]

a[k,j]=a[k,j]−flag×a[i,j],j∈[i,n]

若i<=n,则i=i+1,跳回第1−2步。否则将得到如下形式的矩阵(左半部分左下元素全为0):

初始i=m,将第i行的所有元素a[i,j],j∈[i,n]除以a[i,i]。

枚举第1行至第i−1行,将第k∈[1,i−1]行的元素进行初等变换:

flag=a[k,i]

a[k,j]=a[k,j]−flag×a[i,j],j∈[k,n]

若i>0,则i=i−1,跳回第4−5步。否则将得到如下形式的矩阵(左半部分右上元素全为0):

最终,左半部分的矩阵即为单位矩阵,右半部分的矩阵即为A

−1

初等列变换求逆矩阵

通过初等列变换可以将形如的矩阵转换为形如的矩阵。具体步骤同初等行变换类似。

编程要求

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

在Elementary_Row_Transformation中,矩阵R的左半部分是原矩阵,右半部分是单位矩阵,借助矩阵初等行变换,将矩阵R的左半部分变换为单位矩阵,右半部分变换为原矩阵的逆矩阵。

在Elementary_Col_Transformation中,矩阵C的上半部分是原矩阵,下半部分是单位矩阵,借助矩阵初等列变换,将矩阵C的上半部分变换为单位矩阵,下半部分变换为原矩阵的逆矩阵。

测试说明

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

以下是平台的测试样例:

测试输入:

2

1 2

3 4

预期输出:

1.0000 0.0000 -2.0000 1.0000

0.0000 1.0000 1.5000 -0.5000

1.0000 0.0000

0.0000 1.0000

-2.0000 1.0000

1.5000 -0.5000

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

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

#include <iostream>
#include <algorithm>

using namespace std;

#define eps 1e-8
inline int sig(double x){return (x>eps)-(x<-eps); }

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("%.4lf", this->val[i][0]+eps);
            for(int j=1;j<n;j++){
                printf(" %.4lf", this->val[i][j]+eps);
            }
            printf("\n");
        }
    }
    
    Matrix Elementary_Row_Transformation (){
        
        Matrix R = Matrix(this->n, this->n*2);
        for(int i=0;i<this->n;i++){
            for(int j=0;j<this->n;j++)
                R.val[i][j] = this->val[i][j];
            for(int j=this->n;j<this->n*2;j++)
                R.val[i][j] = ((j-this->n)==i)?1:0;
        }
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
        for(int i=0;i<R.m;i++){
            double flag = R.val[i][i];
            for(int j=i;j<R.n;j++){
                R.val[i][j] /= flag;
            }
            for(int k=i+1;k<R.m;k++){
                flag = R.val[k][i];
                for(int j=i;j<R.n;j++){
                    R.val[k][j] -= flag * R.val[i][j];
                }
            }
        }
       
        for(int i=R.m-1;i>=0;i--){
            double flag = R.val[i][i];
            for(int j=i;j<R.n;j++){
                R.val[i][j] /= flag;
            }
            for(int k=i-1;k>=0;k--){
                flag = R.val[k][i];
                for(int j=k;j<R.n;j++){
                    R.val[k][j] -= flag * R.val[i][j];
                }
            }
        }

        /********* End *********/
        
        return R;
    }
    
    Matrix Elementary_Col_Transformation (){
        
        Matrix C = Matrix(this->n*2, this->n);
        for(int j=0;j<this->n;j++){
            for(int i=0;i<this->n;i++)
                C.val[i][j] = this->val[i][j];
            for(int i=this->n;i<this->n*2;i++)
                C.val[i][j] = ((i-this->n)==j)?1:0;
        }
        // 请在这里补充代码,完成本关任务
        /********* Begin *********/
        for(int j=0;j<C.n;j++){
            double flag = C.val[j][j];
            for(int i=j;i<C.m;i++){
                C.val[i][j] /= flag;
            }
            for(int k=j+1;k<C.n;k++){
                flag = C.val[j][k];
                for(int i=j;i<C.m;i++){
                    C.val[i][k] -= flag * C.val[i][j];
                }
            }
        }
        
        for(int j=C.n-1;j>=0;j--){
            double flag = C.val[j][j];
            for(int i=j;i<C.m;i++){
                C.val[i][j] /= flag;
            }
            for(int k=j-1;k>=0;k--){
                double flag = C.val[j][k];
                for(int i=j;i<C.m;i++){
                    C.val[i][k] -= flag * C.val[i][j];
                }
            }
        }

        /********* End *********/
        
        return C;
    }
};

int main(int argc, const char * argv[]) {

    int n;
    scanf("%d", &n);
    Matrix A(n,n);
    A.in();
    
    Matrix R = Matrix(n, n*2);
    R = A.Elementary_Row_Transformation();
    R.out();
    printf("\n");
    
    Matrix C = Matrix(n*2, n);
    C = A.Elementary_Col_Transformation();
    C.out();
    printf("\n");
    
    return 0;
}
相关推荐
20岁30年经验的码农11 分钟前
爬虫基础
1024程序员节
licy__31 分钟前
计算机网络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程序员节
边疆.2 小时前
C++类和对象 (中)
c语言·开发语言·c++·算法