高斯-约旦消元法

高斯-约旦消元法

此算法是基于高斯消元的基础上改进而成的,唯一不同之处是多进行了几次矩阵变换使得化为行最简型矩阵。相比于高斯消元法此方法效率较低,但是不需要回带求解

此算法的过程大概为:首先确定每个 a [ i ] [ i ] a[i][i] a[i][i]不为 0 0 0(如果为 0 0 0就和下面的行替换),接着将每个 a [ i ] [ i ] a[i][i] a[i][i]通过行变换化为 1 1 1(该行都除以 a [ i ] [ i ] a[i][i] a[i][i]),然后通过行变换将每列除了 a [ i ] [ i ] a[i][i] a[i][i]以外的都消成 0 0 0,重复 n n n次即可

如下是一个求解过程的示例:
在这里插入图片描述
首先最简单的操作是输入增广矩阵:

scanf("%d",&n);
for(int i=1;i<=n;i++)
  for(int j=1;j<=n+1;j++)
  scanf("%lf",&a[i][j]);

接下来开始消元的第一步:判断是否有解

我们每次考虑 a [ i ] [ i ] a[i][i] a[i][i],先看该列的元素是否全为 0 0 0。第二次以后时我们都没有考虑该列上面得到元素,因为他们已经可以被化简为 0 0 0

for(int i=1;i<=n;i++){
	tmp=i;
    // 一直找第i列第tmp行的首个非零元素
	while(fabs(a[tmp][i])<esp && tmp<=n) tmp++;
	if(tmp==n+1) return false;  //如果n行的第i列全判断过仍然没有找到,说明无解
}

消元的第二步:找到该列第一个非零元素后将该行和第 i i i行元素作行交换

我们上面判断是否有解实际上是在找第 i i i列第一个非零元素

//将第tmp行第i列元素不为0的那一行与当前第i行交换
for(int j=1;j<=n+1;j++)
	swap(a[i][j],a[tmp][j]);

消元的第三步:将第 i i i行第 i i i列的元素化为 1 1 1

方法是当前行的所有元素都除以 a [ i ] [ i ] a[i][i] a[i][i]

double p=a[i][i];
for(int j=1;j<=n+1;j++)
	a[i][j]=a[i][j]/p;

消元的第四步:将第 i i i列除了第 i i i行的元素全消成 0 0 0

方法是第 j j j行每个元素 a [ j ] [ k ] a[j][k] a[j][k]都减去 a [ j ] [ k ] ∗ a [ i ] [ k ] a[j][k]*a[i][k] a[j][k]a[i][k]

for(int j=1;j<=n;j++){
	if(i!=j){
		double t=a[j][i];
		for(int k=1;k<=n+1;k++)
			a[j][k]-=t*a[i][k];
	}
}

其实上面四步写在一个 f o r for for循环即可,因此得到该函数:

const double esp=1e-8;
double a[1005][1005];

bool gauss(int n){
    int tmp;
    for(int i=1;i<=n;i++){
        tmp=i;
        while(fabs(a[tmp][i])<esp && tmp<=n)
        tmp++;
        if(tmp==n+1) return false;
        for(int j=1;j<=n+1;j++)          
            swap(a[i][j],a[tmp][j]);
        double p=a[i][i];                
        for(int j=1;j<=n+1;j++)
            a[i][j]=a[i][j]/p;         
        for(int j=1;j<=n;j++){
            if(i!=j){
                double q=a[j][i];
                for(int k=1;k<=n+1;k++)
                a[j][k]-=q*a[i][k];
            }
        }
    }
    return true;
}

如果有多个解的情况呢?如果某变量有多个解,那么该行的 n + 1 n+1 n+1个数一定都等于0

因为每次我们都先保证前面的 a [ i ] [ i ] a[i][i] a[i][i]都一定要为 1 1 1,因此一定在最后几个 a [ i ] [ i ] a[i][i] a[i][i]。看题目要求我们将通解设置为某些常量,而且还需要注意上面有不会完全消为 0 0 0的项,那么我们就需要代入通解求解。

下面是存在一个通解并且将其设置为1的例子:
在这里插入图片描述

void solve(){
    if(fabs(a[col][col])>esp){      //有唯一解
        for(int i=1;i<=col;i++) x[i]=fabs(a[i][col+1]);
        return;
    }
    //否则肯定最后一个是不定解,由于求最小的整数解那么即为1
    x[col]=1;
    for(int i=1;i<col;i++){
        x[i]=fabs(a[i][col]);
    }
}

bool gauss(int n){
    int tmp;
    for(int i=1;i<=n;i++){
        print();
        tmp=i;
        while(a[tmp][i]==0 && tmp<=n) tmp++;
        if(tmp==n+1) return false;
        for(int j=1;j<=n+1;j++)
            swap(a[i][j],a[tmp][j]);
        double p=a[i][i];
        for(int j=1;j<=n+1;j++)
            a[i][j]=a[i][j]/p;
        for(int j=1;j<=n;j++){
            if(i!=j){
                double q=a[j][i];
                for(int k=1;k<=n+1;k++)
                a[j][k]-=q*a[i][k];
            }
        }
    }
    solve();
    return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值