数论-----------高斯消元

输入一个包含n个方程n个未知数的线性方程组。
方程组中的系数为实数。
求解这个方程组。
下图为一个包含m个方程n个未知数的线性方程组示例:
在这里插入图片描述
输入格式
第一行包含整数n。
接下来n行,每行包含n+1个实数,表示一个方程的n个系数以及等号右侧的常数。
输出格式
如果给定线性方程组存在唯一解,则输出共n行,其中第i行输出第i个未知数的解,结果保留两位小数。
如果给定线性方程组存在无数解,则输出“Infinite group solutions”。
如果给定线性方程组无解,则输出“No solution”。
数据范围
1 ≤ n ≤ 100
所有输入系数以及常数均保留两位小数,绝对值均不超过100。
输入样例:
3
1.00 2.00 -1.00 -6.00
2.00 1.00 -3.00 -9.00
-1.00 -1.00 2.00 7.00
输出样例:
1.00
-2.00
3.00

高斯消元 O(n3)

  • 通过初等行变换 把 增广矩阵 化为 阶梯型矩阵 并回代 得到方程的解
  • 适用于求解 包含n 个方程,n 个未知数的多元线性方程组

前置知识:初等行(列)变换

  1. 把某一行乘一个非0的数 (方程的两边同时乘上一个非0数不改变方程的解)
  2. 交换某两行 (交换两个方程的位置)
  3. 把某行的若干倍加到另一行上去 (把一个方程的若干倍加到另一个方程上去)

接下来,运用初等行变换,把增广矩阵,变为阶梯型矩阵

算法步骤

  • 枚举每一列c
    1. 找到当前列绝对值最大的一行
    2. 用初等行变换把这一行换到最上面(未确定阶梯型的行,并不是第一行)
    3. 用初等行变换将该行的第一个数变成 1 (其余所有的数字依次跟着变化)
    4. 用初等行变换将下面所有行的当且列的值变成 0
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    static int N = 110;
    static double eps = 1e-6;
    static int n;
    static double a[][] = new double[N][N];
    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(bf.readLine());
        for (int i = 0; i < n; i ++ )
        {
            String[] str = bf.readLine().split(" ");
            for (int j = 0; j < n + 1; j ++ )
                a[i][j] = Double.parseDouble(str[j]);
        }

        int t = gauss();

        if (t == 0)
        {
            for (int i = 0; i < n; i ++ )
                System.out.printf("%.2f\n", a[i][n]);
        }
        else if (t == 1) System.out.println("Infinite group solutions");
        else System.out.println("No solution");
    }

    private static int gauss() {
        int c;//列
        int r;//行
        //枚举每一列c
        for (c = 0, r = 0; c < n; c ++ )
        {
            //1.找到绝对值最大的一行
            int t = r;//t为绝对值最大的一行
            //遍历每一行
            for (int i = r; i < n; i ++ )
                //比较每一行第c列的值
                if (Math.abs(a[i][c]) > Math.abs(a[t][c]))
                    t = i;//如果找到比之前更大的就更新t值
            //如果绝对值为0,那么这一列所有数都为0,没有必要继续运算
            if (Math.abs(a[t][c]) < eps) continue;
            //2.将绝对值最大的这一行换到最上面
            //从第c列开始是因为第0 ~ c-1列都为0,不需要继续进行交换
            for (int i = c; i < n + 1; i ++ ) swap(a[t][i], a[r][i]);
            //3.将绝对值最大的这一行的第一个系数变为1
            //即等号两边同时除以这个系数,如果从前往后除那么第一个系数除完后为1,后面的也都是除以1了,所以要从后往前除
            for (int i = n; i >= c; i --) a[r][i] /= a[r][c];
            //4.将绝对值最大的这一行的下面所有行的第c列变为0
            for (int i = r + 1; i < n; i ++ )
                if (Math.abs(a[i][c]) > eps) //如果是非0再操作,剪枝
                    //从后往前,当前行的每个数字,都减去对应列 * 行首非0的数字,这样就能保证第一个数字是 a[i][0] -= 1*a[i][0]
                    for (int j = n; j >= c; j -- )
                        a[i][j] -= a[r][j] * a[i][c];
            r ++;//更新r
        }

        //高斯消元后成上三角形式,再迭代回去求解
        //说明剩下的方程小于n个,不是唯一解
        if (r < n)
        {
            //从r ~ n - 1行可能是0 = 非0 或者 0 = 0
            for (int i = r; i < n; i ++ )
                if (Math.abs(a[i][n]) > eps) return 2;//无解
            return 1;//无穷解
        }

        //只有r = n 才是n个方程n个未知数才会有唯一解,迭代求解
        for (int i = n - 1; i >= 0; i -- )
            for (int j = i + 1; j < n; j ++ )
                //要用后面的方程带入前面的方程求解,将前面的方程的未知数变为一个,也就是其他的未知数的系数为0,也就是a[i][n]要减去后面方程倍数的Xn
                a[i][n] -= a[j][n] * a[i][j];
        return 0;//唯一解
    }

    private static void swap(double a, double b) {
        double t = b;
        b = a;
        a = t;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值