行列式计算

在线性代数中,我们接触到了行列式的定义及相关计算,现在我们可以用C语言来帮助我们实现行列式的计算

一起来把这个顽固的行列式算出来(╯‵□′)╯︵┻━┻


行列式计算方式

首先先来回顾一下行列式的计算方式

行列式由定义可知行数和列数相同。对于一个n阶行列式,其行数和列数都是n

a i j 代表行列式中第 i 行第 j 列的元素

 行列式的计算公式

其中 p1p2 ··· pn 为自然数 1, 2, ··· , n 的一个排列,t 为这个排列的逆序数

该公式代表对p1p2 ··· pn所有排列对应的若干项求和,排列数即为项数

那么我们可以将 p1p2 ··· pn 看作n个数在n个数位上进行全排列,然后再执行相应的计算

也就是说,行列式计算需要三步


全排列

在之前的排列专题文章中,已介绍了比较法,记录法,交换法三种排列方法,故这里不再多介绍。

由于行列式行数列数相等,所以排列是全排列,且只是计算就不用考虑按序输出排列,因而推荐使用较快的交换法。

逆序数

  • 比较法

比较法顾名思义就是按照定义,依次将某数前面的数和它比较大小

#include<stdio.h>
void compare(int digit[],int n);int cnt=0;//用于给逆序数计数 int main()
{int n;printf("数的个数:"); scanf("%d",&n);int digit[n];printf("数:"); for(int i=0;i<n;i++) scanf("%d",&digit[i]);compare(digit,n);printf("逆序数:%d",cnt);
} void compare(int digit[],int n)
{for(int i=0;i<n;i++)//i是当前的数的位置 {for(int j=0;j<i;j++)//j是当前的数前面的数的位置 {if(digit[j]>digit[i]) cnt++;}}
}

运行效果图

  • 归并法

归并法利用到了归并排序进行逆序数计算。在之前排序专题的推文中我们已介绍了归并排序。

在这里我们简单回顾一下归并排序的思想。根据分治法的思想,归并排序就是“先分再合”。

先将一个数组无限地一分为二直至不能再分。然后在合并数组的过程中,将每次分割的两个子数组中的元素进行比较,根据顺序依次将元素放到新数组中。重复此步骤直至合并成原来数组的长度。

那么在合并数组过程中的数组元素比较就可以顺便计算逆序数。

#include<iostream>
using namespace std;void mergesort(int temp_digit[],int L,int R);int cnt=0;//用于给逆序数计数 int main()
{int n;cout<<"排序的数的个数:";cin>>n;int temp_digit[n];cout<<"准备排序的数:";for(int i=0;i<n;i++) cin>>temp_digit[i];mergesort(temp_digit,0,n-1);cout<<"经排序过的数:";for(int i=0;i<n;i++) cout<<temp_digit[i]<<" ";cout<<endl<<"逆序数:"<<cnt;
} void mergesort(int temp_digit[],int L,int R)//L,R分别为当前数组的首尾位置
{if(L==R) return;//当数组只剩一个数(无法再分割时),返回 int middle=(L+R)/2;//将当前数组一分为二mergesort(temp_digit,L,middle);//对子数组同样一分为二,直到数组无法再分割 mergesort(temp_digit,middle+1,R);int temp[R-L+1];//临时数组,用于暂时存放排好序的数//达到排序并合并两子数组的效果 int pos1=L,pos2=middle+1,pos3=0;//pos1是在子数组1中的当前位置//pos2是在子数组2中的当前位置//pos3是在临时数组中的当前位置 while(pos1<=middle&&pos2<=R){//两子数组中的数进行比较,较小的数放在临时数组前面 if(temp_digit[pos1]<=temp_digit[pos2]) {temp[pos3++]=temp_digit[pos1++];}else{temp[pos3++]=temp_digit[pos2++];cnt+=middle-pos1+1;//当子数组2当前位置的数比子数组1当前位置的数小时(不能有等于)//子数组1中剩余的数的个数加入逆序数计数中 }} while(pos1<=middle)//将比较后子数组1剩余的数放进临时数组 {temp[pos3++]=temp_digit[pos1++];}    while(pos2<=R)//将比较后子数组2剩余的数放进临时数组 {temp[pos3++]=temp_digit[pos2++];}for(int i=0;i<pos3;i++)//将临时数组排好序的数放回原数组{temp_digit[L+i]=temp[i];}
}

运行效果图

公式计算

结合全排列,逆序数,公式即可进行行列式计算

下面的代码以交换法实现全排列和归并法实现逆序数计算为例,这样当行列式阶数n较大时,计算速度相对较快

#include<stdio.h>void swap(int *,int*);
void arrange(int [],int [],int [],int,int);
void mergesort(int [],int,int);int cnt=0;//cnt用于逆序数计数
int term_cnt=0;//term_cnt用于项数计数
int ans=0;//ans为行列式计算结果int main()
{int n;printf("行列式阶数:");scanf("%d",&n);int digit[n];int temp_digit[n];//temp_digit是digit的临时副本,用于给归并法排序来算逆序数 int det[n*n];//为方便将数组传入函数,用一维数组det存储行列式元素 //行列式中i行j列元素为数组det中第i*n+j个元素 printf("\n行列式:\n");for(int i=0;i<n;i++){for(int j=0;j<n;j++){scanf("%d",&det[i*n+j]);}}for(int i=1;i<=n;i++){digit[i-1]=i;}printf("\n行列式计算式的项:\n");arrange(det,digit,temp_digit,n,0);printf("\n行列式计算式项数:%d\n\n",term_cnt);printf("行列式计算结果为:%d",ans);return 0;
}void swap(int *x,int *y)//交换
{int temp;temp = *x;*x = *y;*y = temp;
}void arrange(int det[],int digit[],int temp_digit[],int n,int pos)
{//arrange是用交换法对a1p1 a2p2...anpn(n和pn都是下标)中的p1p2...pn进行全排列 if(pos==n-1)//到最后一位时,开始套公式计算行列式 {int term=1;//term重置为1 for(int i=0;i<n;i++)//此处循环中的i+1是aij的i,digit[i]是j(在数组中下标都减一){term*=det[i*n+digit[i]-1];//term是当前的项 }//为了不改变原排列的顺序,需要用一个临时数组作为原排列的副本     for(int i=0;i<n;i++)temp_digit[i]=digit[i];cnt=0;//cnt重置为0 //将临时数组传入归并法,用于临时排序的同时计算逆序数 mergesort(temp_digit,0,n-1);term_cnt++;//项数+1 if(cnt%2==1)//若逆序数为奇数,则当前项前有负号 {printf(" -");ans=ans-term;}else if(cnt%2==0)//若逆序数为偶数,则当前项前有正号 {printf(" +");ans=ans+term;}for(int i=0;i<n;i++) {//用a(i,j)表示行列式中第i行第j列的元素//将每一项(包括前面的正负符号)输出,展现计算过程 printf(" a(%d,%d) ",i+1,digit[i]);if(i!=n-1) printf("*");}printf("\n");}else{for(int i=pos;i<n;i++)//i是当前位pos后面的位 {swap(digit+i,digit+pos);//digit[i]和digit[pos]交换 arrange(det,digit,temp_digit,n,pos+1);//进入到下一位的排列 swap(digit+i,digit+pos);//还原交换的两数 }}
}void mergesort(int temp_digit[],int L,int R)//L,R分别为当前数组的首尾位置
{if(L==R) return;//当数组只剩一个数(无法再分割时),返回 int middle=(L+R)/2;//将当前数组一分为二mergesort(temp_digit,L,middle);//对子数组同样一分为二,直到数组无法再分割 mergesort(temp_digit,middle+1,R);int temp[R-L+1];//临时数组,用于暂时存放排好序的数//达到排序并合并两子数组的效果 int pos1=L,pos2=middle+1,pos3=0;//pos1是在子数组1中的当前位置//pos2是在子数组2中的当前位置//pos3是在临时数组中的当前位置 while(pos1<=middle&&pos2<=R){//两子数组中的数进行比较,较小的数放在临时数组前面 if(temp_digit[pos1]<=temp_digit[pos2]) {temp[pos3++]=temp_digit[pos1++];}else{temp[pos3++]=temp_digit[pos2++];cnt+=middle-pos1+1;//当子数组2当前位置的数比子数组1当前位置的数小时(不能有等于)//逆序数计数加上子数组1中剩余的数的个数}} while(pos1<=middle)//将比较后子数组1剩余的数放进临时数组 {temp[pos3++]=temp_digit[pos1++];}  while(pos2<=R)//将比较后子数组2剩余的数放进临时数组 {temp[pos3++]=temp_digit[pos2++];}for(int i=0;i<pos3;i++)//将临时数组排好序的数放回原数组 {temp_digit[L+i]=temp[i];}
}

运行效果图

以a(i , j)表示行列式中第 i 行第 j 列元素

全排列,逆序数与行列式的二三事相关推荐

  1. 全排列与逆序数的组合

    之前也做过这类题,现在做又忘了,整理一下. ACM中遇到逆序数最多的就是 全排列+逆序数 引入 这样一题: 给出n个数字,求使用冒泡排序所需要交换的次数(n到5e5)(POJ2299) 问题可以转化为 ...

  2. 互换矩阵任意两行(列),行列式变号——证明:互换排列中任意两个数,排列逆序数的奇偶性改变

    关于排列的一个简单结论证明---互换排列中任意两个数,排列的逆序数奇偶性改变 一. 引言:在大学线性代数中,有关于行列式的一个常见的定理:*互换任意两行(列),行列式变号.*由行列式完全展开式可以很明 ...

  3. 二叉树:二叉搜索树实现 逆序数问题

    关于逆序数的问题描述如下: 已知数组nums,求新数组count,count[i]代表了在nums[i]右侧且比 nums[i]小的元素个数. 例如: nums = [5, 2, 6, 1], cou ...

  4. 001 线性代数之行列式:定义、逆序数、余子式与代数余子式、n个易算行列式、范德蒙行列式

    001 线性代数之行列式:定义.逆序数.余子式与代数余子式.n个易算行列式.范德蒙行列式

  5. 八十二、归并排序求取复杂的逆序数

    @Author:Runsen 逆序数,我在很多的面试题都见过,本质上来说难度是比较大,因为如果使用暴力法当数据量一大,必然就会爆掉.你现在就要记住逆序数就是考归并排序. 逆序数 给定一个数组array ...

  6. 归并算法经典应用——求解逆序数

    本文始发于个人公众号:TechFlow,原创不易,求个关注 在之前介绍线性代数行列式计算公式的时候,我们曾经介绍过逆序数:我们在列举出行列式的每一项之后,需要通过逆序数来确定这一项符号的正负性.如果有 ...

  7. XTU 2021计网期中测试-冰冰的逆序数

    链接:登录-专业IT笔试面试备考平台_牛客网 来源:牛客网 题目描述 冰冰是木木的妹妹,她读二年级,她的老师出了一道逆序数的题. 逆序数定义如下: 给定一个数列{a1​,a2​,a3​...an​}, ...

  8. 逆序数问题(归并排序,C++)

    在求解八数码问题时,因为要进行逆序数的计算判断两个结点的可达性,同奇偶的逆序数才能可达.如果只是八数,暴力解法还好,当数字多了之后如何知道逆序数呢. 题目描述 通过计算八数码节点的逆序数判断.如果一对 ...

  9. hdu 5273 Dylans loves sequence 逆序数 区间dp

    点击打开链接 题意:给n个数,q次询问,(L,R)区间内的逆序数. 思路: 区间dp 代码一: 1 #include <bits/stdc++.h> 2 using namespace s ...

最新文章

  1. gevent.hub.LoopExit: ('This operation would block forever'
  2. 利用霍夫变换做直线检测的原理及OpenCV代码实现
  3. 远程linux的几个工具
  4. SAP关于销售来自可选工厂的解决方案
  5. APT***的那些事
  6. python traceback什么意思_浅谈Python traceback的优雅处理
  7. 查询Linux系统网卡流量负载,超好用linux系统查询网卡等流量参数的工具,分享给大家!!!...
  8. 经典SQL[私家珍藏]
  9. 网易游戏开发工程师笔试题
  10. Linux之YUM方式安装SVN
  11. MATLAB显示图像变白问题
  12. linux设备驱动的实现与理解
  13. 相较于本地渲染,云渲染用起来感觉怎么样?
  14. session钝化活化
  15. AI 可以从人类思维中学习的11个启示
  16. 搭建自己的github.io博客
  17. 实景三维可视化管理平台助力提升景区运营管理水平
  18. Jmeter对Web Socket进行压力测试 —— 200人直播课实战经验
  19. python实现守护进程_Python如何实现守护进程的方法示例
  20. 告诫程序员们,大三/大四有必要去实习吗?

热门文章

  1. Zynq-7000系列之linux开发学习笔记:编译Linux内核和制作设备树(六)
  2. 数字图像处理——图像采集和预处理
  3. 2017年哈工大数理逻辑期末考试参考答案
  4. Arduino编译Marlin1.1出现 fatal error: U8glib.h: No such file or directory如何解决
  5. /lib64/libstdc++.so.6: version `CXXABI_1.3.8’ not found
  6. c语言莹源码,exp5/wc/client.c · 张雪莹20175227/ISSDF - Gitee.com
  7. 30天自制操作系统 Day3
  8. 熬夜加班赚钱?放弃吧,你的基因里有一个大写的穷。
  9. Google的云计算
  10. HCIA-第八节0615