高斯消元(自由元,无解)

文章目录

        • 题目
            • 描述:
            • 输入:
            • 输出:
        • 基本思想
        • 无解情况
        • 自由元情况

题目

描述:

给出一个线性方程组,有n个方程组,m个未知数。解这个线性方程组。

输入:

第1行:2个整数n和m,(n, m <=400,且n不一定等于m)
接下来n行,每行m+1个整数,表示一个方程的m个未知数的系数和常数(数值不超过1000)

输出:

如果无解,输出“No solution”。
如果有唯一解,输出m行,每行一个未知数的值,保留到小数点第4位。格式见样例。
如果有无穷解,输出m行,如果未知数有确定解,直接输出。如果是自由变元,输出“xx not determined ”格式见样例。
样例输入1:
3 3
2 -1 3 1
4 2 5 4
2 0 2 6
样例输出1:
X[1] = 9.0000
X[2] = -1.0000
X[3] = -6.0000

样例输入2:
3 3
2 -1 3 1
4 -2 5 4
2 -1 4 -1
样例输出2:
X[1] not determined
X[2] not determined
X[3] = -2.0000

样例输入3:
3 4
5 -1 2 1 7
2 1 4 -2 1
1 -3 -6 5 0
样例输出3:
No solution

基本思想

{ 2 x 1 − 1 x 2 + 3 x 3 = 1 4 x 1 + 2 x 2 + 5 x 3 = 4 2 x 1 + 0 x 2 + 2 x 3 = 6 \begin{cases} 2x_1 - 1x_2 + 3x_3 = 1\\ 4x_1 + 2x_2 + 5x_3 = 4\\ 2x_1 + 0x_2 + 2x_3 = 6 \end{cases} 2x11x2+3x3=14x1+2x2+5x3=42x1+0x2+2x3=6
对于上面这个方程,我们想要将其化成这个样式:
{ c 1 x 1 + 0 x 2 + 0 x 3 = v a l 1 0 x 1 + c 2 x 2 + 0 x 3 = v a l 2 0 x 1 + 0 x 2 + c 3 x 3 = v a l 3 ⇒ { c 1 x 1 + 0 + 0 = v a l 1 0 + c 2 x 2 + 0 = v a l 2 0 + 0 + c 3 x 3 = v a l 3 \begin{cases} c_1x_1 + 0x_2 + 0x_3 = val_1\\0x_1 + c_2x_2 + 0x_3 =val_2\\0x_1 + 0x_2 + c_3x_3 = val_3\end{cases} \Rightarrow \begin{cases} c_1x_1 + 0 + 0 = val_1\\0 + c_2x_2 + 0 = val_2\\0 + 0 + c_3x_3 = val_3\end{cases} c1x1+0x2+0x3=val10x1+c2x2+0x3=val20x1+0x2+c3x3=val3c1x1+0+0=val10+c2x2+0=val20+0+c3x3=val3
即把其他项的系数都消为零,所以方程的解就为:
{ x 1 = v a l 1 / c 1 x 2 = v a l 2 / c 2 x 3 = v a l 3 / c 3 \begin{cases} x_1 = val_1/c_1\\x_2= val_2/c_2\\x_3 = val_3/c_3\end{cases} x1=val1/c1x2=val2/c2x3=val3/c3
所以我们对于第 i i i个方程,我们就用 x i x_i xi的系数来对其他 n − 1 n-1 n1个方程消元,以下几点要注意:
1、我们要对每一个 x x x我们都要进行一次消元
2、对于其他 n − 1 n-1 n1个方程中的 x p ( i ! = p ) x_p(i!=p) xp(i!=p)的系数,我们也要相应的消一部分(或加),而 v a l p val_p valp也要消(或加)
3、对于精度问题,我们将现在方程中 x i x_i xi系数的绝对值最大的方程与第 i i i个方程互换,用它的系数来进行对其他 n − 1 n-1 n1个方程的消元(从分数上来说,这样对方程的解无影响,小数就不一定了)
代码大概长这样:注意:这仅仅是消元

int now = 1, k = 1; ————now表示第几个未知数,k表示第几个方程
for(k = 1; k <= n && now <= m;  k ++, now ++){
    int j = k;
    for(int i = k + 1; i <= n; i ++){
    	if( fabs(a[j][now]) < fabs(a[i][now]) )
        	j = i;
    }
    if( fabs(a[j][now]) < 1e-7 ){
    	k --;————第now个x已经消过了,而这一行方程还有用,所以就直接消下一个x
    	continue;————也可以间接说明这个未知数为自由元
    }
    if( j != k )————把绝对值最大的放在第k行
        for(int i = 1; i <=m+1; i ++)
        	swap(a[j][i] , a[k][i]);
    for(int i = 1; i <= n; i ++){
    	if( fabs(a[i][now]) > 1e-7 && i != k ){————对其他n-1个方程消元
        	double t = a[i][now]/a[k][now];————系数比
            for( int j = now; j <= m+1; j ++ )
            	a[i][j] -= t * a[k][j];
    	}
	}
}

无解情况

我们知道若方程有 n n n个未知数,那么就需要 p ( p > n ) p(p>n) pp>n个方程,因为我们只消 n n n个元,因此若方程有解那么剩下 p − n p-n pn个方程的 v a l val val肯定为0
毕竟不会出现这种情况 0 ∗ x 1 + 0 ∗ x 2 + 0 ∗ x 3 = v a l ( v a l ≠ 0 ) 0*x_1+0*x_2+0*x_3 =val (val\neq0) 0x1+0x2+0x3=val(val̸=0)
因此只需要判断剩下方程中的 v a l val val是否为零,是的话就无解了

for( int i = k; i <= n; i ++ ){
	if( fabs(a[i][m+1]) > 1e-6 ){
		printf("No solution");
		exit(0);
	}
}

自由元情况

我们用 v i v_i vi来存储 x i x_i xi是否为自由元( v i = 1 v_i=1 vi=1表示 x i x_i xi为确定元)
我们就检查前 k − 1 k-1 k1个以解出的方程,若方程中只有一个未知数的系数不为零,我们就解出这个未知数,并把 v i v_i vi记为1,为后面的解方程做铺垫;若方程中有多个(>1)未知数无法确定,我们就不处理这个方程,再把前 k − 1 k-1 k1个方程全部解完后,我们再解一遍就行了

if( k <= m ){
        for(int i = 1; i < k; i ++ ){
            int sum = 0 , by = 0;
            for(int j = 1; j <= m; j ++ ){
                if( fabs(a[i][j]) > 1e-7 && !v[j] ){
                    sum ++;
                    by = j;
                }
            }
            if( sum > 1 )
                continue;
            double temp = a[i][m+1];
            for( int j = 1; j <= m; j ++ ){
                if( j != by && fabs(a[i][j]) > 1e-7 )
                    temp -= a[i][j] * x[j];
            }
            x[by] = temp / a[i][by];
            v[by] = 1;
        }
        return ;
    }
    for( int i = m; i >= 1; i -- ){
        double tmp = a[i][m+1];
        for( int j = i + 1; j <= m; j ++ )
            tmp -= a[i][j] * x[j];
        x[i] = tmp/a[i][i];
        v[i] = 1;
    }

你可能感兴趣的:(数论,题解)