我是靠谱客的博主 成就冬日,最近开发中收集的这篇文章主要介绍.高斯消元,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

假如要解n元1次方程组,将n个方程放入一个n*n的矩阵,矩阵的每个位置代表未知数的系数,再写一个答案矩阵,记录每个方程的解,然后将矩阵用方程组的性质(加,乘)化为一个阶梯矩阵,如同下图

begin{bmatrix} 1 & * & *\ 0 & 1& *\ 0& 0 &1 end{bmatrix}=begin{bmatrix} x\ y\z end{bmatrix}

这时可以发现,最后一个方程只有最后一个未知数的系数为1,其余都为0,所以可以知道最后的未知数的值,然后用已知的未知数的值一步一步向上递推消元,就可以求出方程组的解

当然,方程组可能无解或有无限多个解

无解:有一行出现了形如0=d(d为非0数)的式子

无数解:有一行为0=0,这是说明有另外一行是ax+by=d的形式,故此时方程有无数解

#include<bits/stdc++.h>
using namespace std;
int n;
double a[110][110],ans[110];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) scanf("%lf",&a[i][j]);
scanf("%lf",&ans[i]);
}
for(int i=1;i<=n;i++){
double mx=-1000000.00;
int id;
for(int j=i;j<=n;j++){
if(a[j][i]>mx){
mx=a[j][i];
id=j;
}
}//a矩阵记录了方程每个未知数的系数,ans记录了方程组的答案
for(int j=1;j<=n;j++) swap(a[i][j],a[id][j]);
swap(ans[i],ans[id]);
if(!a[i][i]){
if(ans[i]) printf("No Solution");//出现了0=d这种形式
else printf("wushujie");//出现了0=0这种形式
return 0;
}
ans[i]/=a[i][i];
for(int j=n;j>=i;j--) a[i][j]/=a[i][i];
for(int j=i+1;j<=n;j++){
double ty=a[j][i];
for(int k=1;k<=n;k++) a[j][k]-=ty*a[i][k];
ans[j]-=ty*ans[i];
}
}
for(int i=1;i<=n;i++){
bool ok=false;
for(int j=1;j<=n;j++){
if(a[i][j]) ok=true;
}
if(!ok){
printf("No Solution");
return 0;
}
}
for(int i=n-1;i>=1;i--){
for(int j=i+1;j<=n;j++) ans[i]-=ans[j]*a[i][j];//递推答案
}
for(int i=1;i<=n;i++){
printf("%.2lfn",ans[i]);
}
return 0;
} 

例题 

一个球面上的点到圆心的距离都相等,所以就有

forall_{i} sum_{j=1}^{jleq n}(a_{ij}-x_{j})^{2}=d     

a[i][j]表示球面上第i个点第j维的坐标,x[j]表示圆心第j维的坐标,d是一个固定的数

因为d是固定的,并且有有n+1个这种式子,所以可以让这些式子相减得到n个为0的式子

because sum_{j=1}^{jleq n}(a_{i,j}-x_{j})^{2}-(a_{i,j+1}-x_{j+1})=0

therefore sum_{j=1}^{n}a_{i,j}^{2}+2*x_{j}*a_{i,j}+x_{j}^{2}-a_{i,j+1}^{2}+2*x_{j+1}*a_{i,j+1}-x_{j+1}^{2}=0

therefore sum_{j=1}^{jleq n} 2*x_{j}*(a_{i,j}-a_{i,j+1})=sum_{j=1}^{jleq n} a_{i,j}^{2}-a_{i,j+1}^{2}

这就是高斯消元的形式了,第i行第j位的值为2*x[j]*(a[i][j]-a[i][j+1]),答案的值为a[i][j]的平方减a[i][j+1]的平方的差的和

#include<bits/stdc++.h>
using namespace std;
int n;
double k[110][110],a[110][110],ans[110];
int main(){
scanf("%d",&n);
for(int i=1;i<=n+1;i++){
for(int j=1;j<=n;j++){
scanf("%lf",&a[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
k[i][j]=2.00*(a[i][j]-a[i+1][j]);//每一位的系数
ans[i]=ans[i]+a[i][j]*a[i][j]-a[i+1][j]*a[i+1][j];
}
}
for(int i=1;i<=n;i++){
double mx=-10000000.00;
int id;
for(int j=i;j<=n;j++){
if(mx<k[j][i]){
mx=k[j][i];
id=j;
}
}
for(int j=1;j<=n;j++) swap(k[i][j],k[id][j]);
swap(ans[i],ans[id]);
ans[i]/=k[i][i];
for(int j=n;j>=i;j--) k[i][j]/=k[i][i];
for(int j=i+1;j<=n;j++){
double bs=k[j][i];
for(int h=1;h<=n;h++) k[j][h]-=bs*k[i][h];
ans[j]-=bs*ans[i];
}
}
for(int i=n-1;i>=1;i--){
for(int j=i+1;j<=n;j++){
ans[i]-=ans[j]*k[i][j];
}
}
for(int i=1;i<=n;i++){
printf("%.3lf ",ans[i]);
}
return 0;
}

异或运算的高斯消元

比如说有3个未知数和几个式子,那么矩阵每一位就表示在这个式子中xi是取还是不取

可以将矩阵压成一个数,这样可以缩小时间复杂度

每次找到最大的数来更新

和普通高斯消元一样,使第i位为1,1~i-1位为0


 

题面上说对2取模,相当于就是这一堆数异或后最后一位的值

n达到了1000,只能用bitset来表示每一位的状态

对于第i位,找到第一个第i位为1的式子来更新答案

/*bitset对高斯消元的优化
对于只有异或运算的高斯消元,可以用bitset将状态压为一个数,使得时间复杂度降倒1/32
找最大值时候就枚举要找的位数就行
*/
#include<bits/stdc++.h>
using namespace std;
bitset<1010>a[2010];
int m,n,c,ans,pd[2010];
int main(){
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char ch=getchar();
while(ch!='0'&&ch!='1') ch=getchar();
a[i][j]=ch-'0';
}
int w;
scanf("%d",&w);
a[i][m+1]=w;
}
for(int i=1;i<=m;i++){
int j=i;
while(!a[j][i]&&j<=n) j++;
if(j>n){
printf("Cannot Determine");
return 0;
}
ans=max(ans,j);
swap(a[i],a[j]);
for(int j=1;j<=n;j++){
if(i!=j&&a[j][i]) a[j]^=a[i];
}
}
for(int i=m;i>=1;i--){
for(int j=i+1;j<=m;j++){
if(a[i][j]) a[i]^=a[j];
}
pd[i]=a[i][m+1];
}
printf("%dn",ans);
for(int i=1;i<=m;i++){
pd[i]%2?printf("?y7M#n"):printf("Earthn");
}
return 0;
}

最后

以上就是成就冬日为你收集整理的.高斯消元的全部内容,希望文章能够帮你解决.高斯消元所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(37)

评论列表共有 0 条评论

立即
投稿
返回
顶部