数学知识:高斯消元

 用初等行变化得出最简阶梯型矩阵 (第一个数为1)

高斯消元解线性方程组:

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

const int N = 110;
const double eps = 1e-6;//c++有误差,0不一定是0,所以用一个很小的数字当0

int n;
double a[N][N];

int gauss()//化成最简阶梯型矩阵
{
    int c, r;// c 代表 列 col , r 代表 行 row
    for (c = 0, r = 0; c < n; c ++ )
    {
        int t = r;// 先找到当前这一列,绝对值最大的一个数字所在的行号
        for (int i = r; i < n; i ++ )
            if (fabs(a[i][c]) > fabs(a[t][c]))
                t = i;

        if (fabs(a[t][c]) < eps) continue;// 如果当前这一列的最大数都是 0 ,就到下一列去计算(c++但r不加),说明不是绝对不是满秩

        // 把当前这一行的所有数,换到最上面(不是第一行,是第 r 行)去
        for (int i = c; i < n + 1; i ++ ) swap(a[t][i], a[r][i]);
        // 把当前这一行的第一个数(不一定是第一列,而是第一个不为0的数),变成 1, 必须要倒着算
        //因为最左边是要用来给其他列倍乘的,不能发生变化,最后再给自己发生变化变成1
        for (int i = n; i >= c; i -- ) a[r][i] /= a[r][c];
        // 把r行这列下面的所有数,全部消成 0
        for (int i = r + 1; i < n; i ++ )
            if (fabs(a[i][c]) > eps)// 如果非0再操作,已经是0就没必要操作了
                for (int j= n; j >= c; j -- )// 从后往前,i行j列 - 要用的r行j列 * i行的第一个不为0的列
                a[i][j] -=  a[i][c]*a[r][j];//这样能保证该行第一个数一定为0,因为c列只有r行才有并且为1。相当于倍乘操作

        r ++ ;// 这一行的工作做完,换下一行
    }

    //因为从是0开始的,所以r的值本应该是n-1的,但是每次操作后都r++,导致r满秩的时候是=n的
    if (r < n)// 说明剩下方程的个数是小于 n 的,说明不是满秩(唯一解),判断是无解还是无穷多解
    {
        //因为最后一次操作是从r结束的,但是r++了,所以现在的r是最后一次操作的r的下一行
        for (int i = r; i < n; i ++ )//判断上次r行下面的值是不是都是0 ,因为上次r是阶梯最后有数字的行,所以判断上次r的下面所有行的最后一个数是不是0
            //因为上面的for已经把阶梯化成了,但是并不满秩,所以判断每行的最后一列是否有值(因为有可能i行的阶梯的i列为0,他的台阶在i列后面的情况,所以只判断最后一列即可)
            if (fabs(a[i][n]) > eps)//如果出现不是0的,则无解
                return 2;
        return 1;// 否则,无数解
    }
    // 唯一解 ↓,从下往上回代,得到方程的解
    //因为当时是把每个方程的等式右边的值也放进矩阵了,所以n列就是每行的解
    for (int i = n - 1; i >= 0; i -- )//注意是从最后一行开始的,因为最后一行的未知数个数为<=1的,倒数第二行个数为<=2,以此类推
        for (int j = i + 1; j < n; j ++ )//所以把i行下面的i+1的未知数赋予i+1的解,再减去i+1的解得出i的解
            a[i][n] -=  a[i][j]*a[j][n] ;//例:x1+x2+x3=5,把x2、x3当做4来算,算出x1=1
                                         //       x2+x3=4,把x3当做1来算,算出x2=3
                                         //          x3=1,从最后一行开始往上做
    return 0;
}

int main()
{
    scanf("%d",&n);
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n + 1; j ++ )
            cin>>a[i][j];

    int t = gauss();

    if(t==0)
        for(int i=0;i<n;i++)
            if(fabs(a[i][n])<eps)//若答案为0,c++的0并不是0,而是很小的数
                puts("0.00");
            else
                printf("%.2lf\n",a[i][n]);//可能是-0.00
    else if (t == 1) puts("Infinite group solutions");
    else puts("No solution");

    return 0;
}

高斯消元解异或线性方程组:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

int n;
int a[N][N];
int gauss()//化为最简阶梯型矩阵
{
    int c,r;// c 代表 列 col , r 代表 行 row
    for(c=0,r=0;c<n;c++)
    {
        // 找到c列非0的行
        int t=r;
        for(int i=r;i<n;i++)
            if(a[i][c])
            {
                t=i;//找到就可以break
                break;
            }
        if(!a[t][c]) continue;//该列没有非0行,找下一列
        // 把当前这一行的所有数,换到最上面(不是第一行,是第 r 行)去
        for(int j=c;j<=n;j++) swap(a[r][j],a[t][j]);
        //用当前行把下面所有行消成0(化成最简行阶梯)
        for(int i=r+1;i<n;i++)
            if(a[i][c])//若不是0,则进行操作,是0就不用操作了
                for(int j=n;j>=c;j--)//把当前i行j列异或最上面不为0的r行j列
                    a[i][j] ^= a[r][j];
        r++;// 这一行的工作做完,换下一行
    }
     //因为从是0开始的,所以r的值本应该是n-1的,但是每次操作后都r++,导致r满秩的时候是=n的
    if(r<n)
    {
        for(int i=r;i<n;i++)//i=r
            if(a[i][n])//如果出现不是0的,则无解
                return 2;
        return 1;//否则,无数解
    }
    // 唯一解 ↓,从下往上回代,得到方程的解
    //因为当时是把每个方程的等式右边的值也放进矩阵了,所以n列就是每行的解
    for(int i=n-1;i>=0;i--)//注意是从最后一行开始的,因为最后一行的未知数个数为<=1的,倒数第二行个数为<=2,以此类推
        for(int j=i+1;j<n;j++)//所以把i行下面的i+1的未知数赋予i+1的解,再减去i+1的解得出i的解
        //如果是0 就不用下面的a[j][j] 来^a[i][j]了
        //如果不是0 才需要用第j行第j列a[j][j]来^第i行第j列a[i][j] 
        //进而进行整行row[i]^row[j] 间接导致 a[i][n]^a[j][n]
            a[i][n]^=a[i][j]&a[j][n];//例:x2^x3=0,把x1当做1,x2当0来算,算出x3=0
                                 //    x1^x2=1,把x1当1,得x2为0,
                                 //       x1=1,从最后一行开始往上做
    return 0;
}

int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        for(int j=0;j<=n;j++)
            scanf("%d",&a[i][j]);
    int t = gauss();
    if(t==0)
    {
        for(int i=0;i<n;i++) printf("%d\n",a[i][n]);
    }
    else if(t==1) printf("Multiple sets of solutions\n");
    else printf("No solution\n");
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

@katoumegumi

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

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

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

打赏作者

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

抵扣说明:

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

余额充值