高斯消元:
解$n$元一次方程组的通用方法,大部分时候用于解决没有明显转移顺序的dp。
考虑将方程组列成一个$n\times (n+1)$的矩阵$A$,然后依次枚举每一个未知数$j$(第$j$列):
- 从上往下找到第一个$i$,满足$i\geq j,A_{i,j}\neq 0$。
- 如果找不到则该方程组无解,退出。否则把第$i$行与第$j$行交换。
- 对于任意$k\neq j$,用第$j$行消第$k$行,使其满足$A_{k,j}=0$。
显然最后消出的是一个对角线矩阵(只在$A_{i,i}$处不为0),此时方程组的解$x_{i}=\frac{A_{i,n+1}}{A_{i,i}}$。
复杂度$O(n^{3})$。
#include<bits/stdc++.h> #define maxn 505 #define maxm 500005 #define inf 0x7fffffff #define ll long long #define rint register int #define debug(x) cerr<<#x<<": "<<x<<endl #define fgx cerr<<"--------------"<<endl #define dgx cerr<<"=============="<<endl using namespace std; int n; double A[maxn][maxn]; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline bool Gauss(){ for(int j=1;j<=n;j++){ for(int i=j;i<=n;i++){ if(A[i][j]==0) continue; for(int k=1;k<=n+1;k++) swap(A[i][k],A[j][k]); break; } if(A[j][j]==0) return 0; for(int i=1;i<=n;i++){ if(i==j || A[i][j]==0) continue; double x=A[i][j]/A[j][j]; for(int k=1;k<=n+1;k++) A[i][k]-=A[j][k]*x; } } return 1; } int main(){ n=read(); for(int i=1;i<=n;i++) for(int j=1;j<=n+1;j++) A[i][j]=read(); if(!Gauss()) printf("No Solution\n"); else for(int i=1;i<=n;i++) printf("%.2lf\n",A[i][n+1]/A[i][i]); return 0; }