ZigZagKmp
Think twice, code once.

题目传送门

算法分析

高斯消元,是求解\(n\)\(n\)\(1\)次方程组的算法,一般情况下时间复杂度为\(O(n^3)\)

我们把这\(n\)个方程组看成一个\(n\times (n+1)\)的矩阵。以样例为例:

\[ \left( \begin{matrix} {{x}_{1}} & 3\times {{x}_{2}} & 4\times {{x}_{3}} \\ {{x}_{1}} & 4\times {{x}_{2}} & 7\times {{x}_{3}} \\ 9\times {{x}_{1}} & 3\times {{x}_{2}} & 2\times {{x}_{3}} \\ \end{matrix} \right)=\left( \begin{matrix} 5 \\ 3 \\ 2 \\ \end{matrix} \right) \]

我们把答案也写成矩阵的形式,不难发现:我们的目标矩阵应该形如下面

\[\left( \begin{matrix} {{x}_{1}} & 0 & 0 \\ 0 & {{x}_{2}} &0 \\ 0& 0& {{x}_{3}} \\ \end{matrix} \right)=\left( \begin{matrix} -\frac{37}{38} \\ \frac{197}{38} \\ -\frac{91}{38} \\ \end{matrix} \right) \]

我们选择当前没有求解过的一个未知数(设为\(x_i\)),将\(x_i\)前的系数化为\(1\),然后用这样一行方程与其他方程相减相消,使得其他方程\(x_i\)前的系数都为\(0\).

考虑选取\(x_i\),一个最直观的想法是第\(i\)行选取的未知数是\(x_i\),但如果\(x_i=0\),显然就这个方程怎么转化都不会使\(x_i=1\),在这种情况下我们应选取\(x_i\)前系数不为\(0\)的一个方程,并与之交换。如果所有\(x_i\)的系数都是\(0\),那么\(x_i\)有无数解。

当出现\(0=a(a\ne 0)\)的情况,方程无解。

注意中间变量开double型!

代码实现

#include<bits/stdc++.h>
using namespace std;
#define maxn 105
int n;
double a[maxn][maxn];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n+1;j++)scanf("%lf",&a[i][j]);
	for(int i=1;i<=n;i++){
		int p=0;
		for(int j=i;j<=n;j++){if(a[j][i]!=0){p=j;break;}}
		if(!p){puts("No Solution");return 0;}
		for(int j=1;j<=n+1;j++)swap(a[i][j],a[p][j]);
		double k=a[i][i];//错误笔记:中间变量使用int型
		for(int j=1;j<=n+1;j++)a[i][j]/=k;
		for(int j=1;j<=n;j++){
			if(i==j)continue;
			double kk=a[j][i];
			for(int l=1;l<=n+1;l++)a[j][l]-=kk*a[i][l];
		}
	}
	for(int i=1;i<=n;i++)printf("%.2lf\n",a[i][n+1]);
	return 0;
}

posted on 2019-09-08 21:04  ZigZagKmp  阅读(141)  评论(0)    收藏  举报