#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;
}