行列式的辗转相减

目录

前导说水(可以忽略)

正题引入

①高斯消元法

 ②出现的问题

③解决方法

辗转相减法

 ①双指针的建立

②特判对角线元素为0

③判断最后值的正负

最终完整代码

最后牢骚


前导说水(可以忽略)

其实也不是前导啦,就是跟发说说一样,发一些牢骚吧,然后今天也听说了博客其实也是可以发一些与题目无关的事情,但是捏,作为一篇解题博客,还是得点题啊。要不就来说一说辗转的事情吧,什么是辗转啊,很多人在睡觉的时候一定会有辗转反侧的事情,所谓人生也是如此吧。本蒟蒻在前一段时间,也因为失去了一个本来可以很好的朋友而辗转反侧了很久一段时间,在那一段时间里,我发现自己不知道应该怎么去排解自己的忧愁,也不知道如何才能不去想这一件事情,其实思来想去了很久,最终也还是与自己和解了,然后我做了第一次删好友的行为,但是其实不是因为自己还是过不去,只是觉得如果真的没有办法走在一起的朋友,即使自己用什么方式挽留都已经无法去抚平以前的创伤了,所以只能直说“眼不见为净”,希望今后各自安好,希望不要有仇恨,不要有任何的偏见。而那一段渐渐愈合的时间让我真正知道自己在入大学社交上的一些问题,以及投入很多的精力在一些所谓网络上的聊天之上,然后活成了一个不适合自己的我。所以那个时候,我会让自己更加的忙起来,至少在自己忙起来的时候会发现,原来生活是可以如此充实的。在写这一篇文章的时候,感谢博客给自己提供了一个平台,无论是让自己能够静下心来思索以前学过的一些算法也好,还是让自己有一个平台倾诉,也许日后能够让其它如我一般的人看到,得到一些慰藉和一些解惑,真的觉得在一定程度上,这也极大的成为了自己坚持继续写博客的动力吧,然后呢,现在看着自己写的博客,访客量逐渐变多了,希望为自己,也为今后可能看到文章的人,坚持写下去吧!对了,今天换了一个头像呢,因为北京的天对于我这样的南方人来说是真的很冷很冷,但是又怎么样呢,我的心依旧是冰冰的呢!

正题引入

其实看大标题应该就能知道本章文章主要是为了计算行列式的,计算行列式有很多很多的方法,相信很多大一新生在进行线性代数的学习上一定会被计算行列式算废了不少的草稿纸吧,那么请看这篇文章,从此以后,计算行列式只需要一个程序,啊别,大家为了自己的计算能力,还是得自己好好算的哈,毕竟在计算上偷懒绝对没有什么太多的好处的。这里主要为大家介绍高斯消元法哈!

①高斯消元法

大家应当都知道高斯消元法吧,不会有人不知道吧哈哈哈。也就是说,最终的行列式一定可以化简成为一个上三角的形状,那么最后的时候就肯定能够计算出行列的数值(也就是主对角线上元素的乘积)。那么对于下面的行列式,如何高斯消元呢?

25
34

大家会说这不是个二阶的嘛,消元干啥,其实只是为了让大家大家感受一下哈!也就是我们可以利用第一个2乘以一个(-\frac{3}{2})加到第二行上去,然后就可以了鸭。没错,确实就是这样的,高阶的话也可以利用这样的方法,very nice!

 ②出现的问题

可是,我们是用编程去进行这样的操作也,我们难道要利用double的类型去处理一些数据吗?如果是用3去消2呢,岂不是出现了一个3/2的无法表示完的一个小数呢?所以很明显这样的方式是不合理的。

③解决方法

为了解决上述的问题,同学们肯定有所见解吧,大家在进行消元的时候,大概率会把小的那一行放在最前面,然后利用行列式的性质,交换两行行列式取负。再不断的进行消元,如果遇到2,3呢,想必大家会让他们所在的那两行都变成6,然后消掉其中一个变成0,再进行后续的操作,也就是第一种方法,就是可以求出他们的最小公倍数,然后补全到最小公倍数的值之后进行消元,这个留给大家实现,今天介绍一个稍微难理解的一个方法----辗转相减法。

辗转相减法

相信大家对辗转相除法有所了解,所以,相信理解辗转相减法也不会是一个难事。下面我们先看一幅图,其实本题也可以利用双指针,只不过双指针会比较轻松,因为它们只需要在两个地方进行移动。

 ①双指针的建立

还是以消除2,3为例子,其中p1先指向2,p2指向3,然后让p1所处在的值除以p2所处在的值得到p1能够最多减去多少个p2,发现第一次的时候只能减去0个,这个时候p2的值不为0,交换指针,发现可以减去一个了,这个操作其实就是先让3-2,剩下1,2。然后让2-1*2,最后不就完成消去其中的一个元素为0了吗?我们注意到,因为最后消去0的时候是让第二行的1消去了第一行的2,这显然没有达到我们的效果,我们需要第一行第一个元素必须是一个正数,当然如果最后的对角线元素有一个为0,行列式肯定为0了。那么我们看到这个过程,指针的不断交换,让本来的x应该为1,但是最后为2了也就是图中的i变为了j,这也就是代表了我们最后让1停在第二行,也就是完成辗转相减的操作之后,我们要让两行进行一个交换。

for(int i=0;i<n;i++)
	{
		for(int j=i+1;j<n;j++)
		{
			int p1=i,p2=j;
			while(a[p2][i])   //注意此处的停止条件
			{
				long long t=a[p1][i]/a[p2][i];
				for(int k=i;k<n;k++)
				a[p1][k]=(a[p1][k]-a[p1][k]*t);
				swap(p1,p2);
			}

我们关注到,这里外面的第一层循环是对列的循环,而第二层for循环是对行的,这个应该很好理解,然后实现交换的代码如下。

if(p1!=i)
		{
			for(int j=0;j<n;j++)
			swap(a[i][j],a[p1][j]);
			p++;  //p代表交换的次数,便于确定最后行列式值的正负
		}

②特判对角线元素为0

if(a[i][i]==0)
		{
			cout<<0<<endl;
			return;
		}

这里可能会减少最终循环的时间。

③判断最后值的正负

if(p%2!=0) ans*=-1;

其实就是看交换的次数是奇还是偶。

最终完整代码

#include<bits/stdc++.h>
using namespace std;
long long mod;
long long n;
long long p=2; //表示奇数交换多少次,判断最后是否有负号
int a[605][605];
long long ans=1;//ans用来计算最后的结果 
void hls()
{
	for(int i=0;i<n;i++)
	{
		for(int j=i+1;j<n;j++)
		{
			int p1=i,p2=j;
			while(a[p2][i])
			{
				long long t=a[p1][i]/a[p2][i];
				for(int k=i;k<n;k++)
				a[p1][k]=(a[p1][k]-a[p2][k]*t);//%mod;
				swap(p1,p2);
			}
		if(p2!=i)
		{
			for(int j=0;j<n;j++)
			swap(a[i][j],a[p1][j]);
			p++;
		}
		}
		if(a[i][i]==0)
		{
			cout<<0<<endl;
			return;
		}
		else ans=ans*a[i][i];//%mod;
	}
        if(p%2!=0) ans*=-1;
        cout<<endl;
        //if(ans<0) ans+=mod;
		cout<<ans<<endl; 
 }
 int main()
{
	 cin>>n;//>>mod;
	 for(int i=0;i<n;i++)
	 {
	  	for(int j=0;j<n;j++)
		  cin>>a[i][j];	
     }
	 hls();
	 for(int i=0;i<n;i++)
	 {
	  	for(int j=0;j<n;j++)
		  cout<<a[i][j]<<" ";
		  cout<<endl;	
     }
	 return 0; 	
} 

当然在代码块中存在一个mod,是因为有一些算法题目是不会让你计算一个大数的,所以需要对每一步进行取模,在此不加以赘述。 

最后牢骚

发完这篇博客,自己应该可以升级了吧,哎写一篇原创的博客真的挺不容易的,不过还是很有成就感啊,最后这里再附上冰冰的一张美图吧,其实就是我的头像哈哈哈!我保证这不是为了吸粉哈哈,哈。糖葫芦真的好好吃!(冰冰真的好好看啊)

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sheep.ice

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值