洛谷 P3389 【模板】高斯消元法(数论)
传送门
高斯消元
什么叫高斯消元?
就是解多元方程组的一种方法。
给你n个方程组,包含着n个未知数,告诉你每一个方程中的每一个未知数的系数和常数项。
怎么解?
和数学上差不多,把第一个方程保留第一个未知数(设系数为k),把第二个到第n个方程的第一个未知数的系数化为-k,用加减消元即可。
以此类推,枚举到第i个方程保留第i个未知数的系数k(i前面的未知数系数已经化为0),把第i+1到第n个方程的第i个未知数的系数化为-k,加起来消元。
最后就会变成如下形式:
K1*X1+K2*X2+K3*X3+……+Kn*Xn=Kn+1
0*X1+K2'*X2+K3'*X3+……+Kn'*Xn=Kn+1'
………………………………………………
0*X1+0*X2+0*X3+……+0*Xn-1+Kn*Xn=Kn+1
这样就可以从第n个方程往前推,一步步解出所有的未知数。
什么情况有多个解?
当推到某个方程(设为第i个)出现0*Xi=Kn+1
则Xi可以为任意实数。
怎么保证精度?
保证第i个方程Xi的系数最大。(证明略)
AC代码
1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstdio> 5 #include<cstring> 6 #include<iomanip> 7 using namespace std; 8 int n; 9 double a[105][105],ans[105]; 10 int main() 11 { 12 cin>>n; 13 for(int i=1;i<=n;i++){ 14 for(int j=1;j<=n;j++){ 15 cin>>a[i][j]; 16 } 17 cin>>a[i][n+1]; 18 } 19 for(int i=1;i<=n;i++){ 20 int r=i; 21 for(int j=i+1;j<=n;j++){ 22 if(fabs(a[r][i])<fabs(a[j][i])) r=j; 23 } 24 if(i!=r) for(int j=i;j<=n+1;j++) swap(a[i][j],a[r][j]); 25 for(int j=i+1;j<=n;j++){ 26 for(int k=i+1;k<=n+1;k++){ 27 a[j][k]=a[j][k]-a[j][i]/a[i][i]*a[i][k]; 28 } 29 a[j][i]=0; 30 } 31 } 32 for(int i=n;i>=1;i--){ 33 if(a[i][i]==0){ 34 cout<<"No Solution"; 35 return 0; 36 } 37 ans[i]=a[i][n+1]/a[i][i]; 38 for(int j=1;j<i;j++){ 39 a[j][n+1]-=a[j][i]*ans[i]; 40 } 41 } 42 for(int i=1;i<=n;i++) cout<<fixed<<setprecision(2)<<ans[i]<<endl; 43 return 0; 44 }