1.高斯消元
在O(n^3)下求解一个包含n个方程组n个未知数的多元线性方程组
n元线性方程组解的三种情况:无穷多组解、唯一解、无解
对n*(n+1)的增广矩阵做初等行列变换:
1.把某一行乘以一个非零的数
2. 交换某两行
3. 把某行的若干倍加到另一行
如果出现:
1.r(A)=n,即最后的阶梯型恰好是由n个方程式构成的(完美阶梯型n个方程n个未知数)唯一解
2.出现一个方程 0=k (k≠0) 无解
3.出现一些0=0的方程(说明这个方程可以由别的方程表示,是多余的) 无穷多个解
算法步骤:
1.枚举每一列c
(1)找到这一列绝对值最大的那一行
(2)将这一行换到当前未处理的最上面
(3)将该行的第一个数变成1
(4)将下面所有行的第c列消成0
2.消成阶梯型后,判断解的情况,若有唯一解,从下往上带入(消除)求解。
例题1 解线性方程组
输入
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
代码
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=110;
const double eps=1e-7;
int n;
double a[maxn][maxn];
int gauss()
{
int c,r;
for(c=0,r=0;c<n;c++)//遍历每一列
{
int t=r;//t中存放当前最大值所在那一行行标
for(int i=r;i<n;i++)
if(fabs(a[i][c])>fabs(a[t][c]))
t=i;
if(fabs(a[t][c])<eps)//最大值等于0
continue;//说明该列全为0,换下一列进行比较
//交换两行
for(int i=c;i<n+1;i++)//共有n+1列
swap(a[t][i],a[r][i]);
//把那个最大值变为1
for(int i=n;i>=c;i--)//这里应该从后往前,因为那个最大值必须最后一个除,不然会变成都除1
a[r][i]/=a[r][c];//r是当前的最上层
//把该列下面的值都消成0
for(int i=r+1;i<n;i++)
if(fabs(a[i][c])>eps)
for(int j=n;j>=c;j--)
a[i][j]-=a[r][j]*a[i][c];
r++;
}
if(r<n)//有左部全为0的行
{
for(int i=r;i<n;i++)
if(fabs(a[i][n])>eps)//右部不为0
return 2;//无解
return 1;//有0=0,无穷多组解
}
//有唯一解,从下往上消
for(int i=n-1;i>=0;i--)//处理每一行
for(int j=i+1;j<n;j++)//用下面那层消上面那层
a[i][n]-=a[j][n]*a[i][j];//系数是上面那行要被消掉的值a[i][j]
return 0;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n+1;j++)
cin>>a[i][j];
int flag=gauss();
if(flag==0)
{
for(int i=0;i<n;i++)
printf("%.2lf\n",a[i][n]);
}else if(flag==1)
cout<<"Infinite group solutions"<<endl;
else
cout<<"No solution"<<endl;
return 0;
}
例题2 解异或线性方程组
异或也是不进位的加法
输入
3
1 1 0 1
0 1 1 0
1 0 0 1
输出
1
0
0
代码
基本差不多,不过运算从加减乘除变成了异或、与之类的。
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=105;
const int mod=1e9+7;
int n;
int a[maxn][maxn];
int gauss()
{
int c,r;
for(c=0,r=0;c<n;c++)//遍历每一列
{
int t=r;//从当前未处理的行开始
for(int i=r;i<n;i++)
if(a[i][c])
t=i;
if(!a[t][c])//如果该列没有1,换着处理下一列
continue;
for(int i=c;i<=n;i++)
swap(a[r][i],a[t][i]);
for(int i=r+1;i<n;i++)//消除下面其他行的1
if(a[i][c])
{
for(int j=n;j>=c;j--)
a[i][j]^=a[r][j];//两个1异或就变成0了,注意不能用减,不然0-1会出现-1
}
r++;
}
if(r<n)
{
for(int i=r;i<n;i++)
if(a[i][n])
return 2;
return 1;
}
for(int i=n-1;i>=0;i--)//从下往上迭代
for(int j=i+1;j<n;j++)//i=n-1,任何数和0异或都是它本身
a[i][n]^=a[i][j]&a[j][n];//系数a[i][j],或者用*代替咯
return 0;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n+1;j++)
cin>>a[i][j];
int flag=gauss();
if(flag==0)
{
for(int i=0;i<n;i++)
cout<<a[i][n]<<endl;
}else if(flag==1)
cout<<"Multiple sets of solutions"<<endl;
else
cout<<"No solution"<<endl;
return 0;
}