[SDOI2006] 线性方程组

主要记录一下高斯消元解方程的正确写法

希望能:

1.判断唯一解、无穷解、无解

2.求出自由元个数

3.求出哪些是自由元

 

思路就是

1.用vis标记记录每个方程是不是固定的(如果这个方程的某一个未知数的系数用来当“代表”来消其他行的系数,那么这个方程就算是固定的,不要动了,否则会乱)

2.每次找xi系数不是0的且没有vis的方程,找到的话换到第i行,找不到就算了。

3.消除的时候,把每一行的xi系数都消了,不管是不是vis

 

这样得到的上三角矩阵里面,如果a[i][i]为0,那么必然这一行所有未知数系数都是0,因为xj的系数会被其他行消掉(如果没有被消掉,说明其他行xj都是0,那么xj会被选为j的代表,这个方程放到第j行,而不是第i行。)

所以这时如果某行未知数系数都是0,且等式右侧常数非零,则无解;

如果所有行未知数系数都是0的右侧常数也为0,那么无穷多组解。每个这样子的行都是一个自由元,且自由元就是xi

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long double lb;//用double也能过 
const int N=52;
const lb eps=1e-8;//实测eps设为0.01都可以过 
int n;
lb f[N][N];
lb ans[N];
int fl;
bool vis[N];//这个vis表示这一行的向量有没有固定(假如这一行作为某次选定的行,用来消除别的行的未知数,那么这一行就不能动了,vis设为1 
int guass(){
    for(int i=1;i<=n;i++){
        int id=i;
        bool find=false; 
        for(int j=1;j<=n;j++){//这里从第一行开始找。找所有vis是0的情况。 
            if(vis[j]==0&&fabs(f[j][i])>fabs(f[id][i])){
                id=j;
            }
        }
        if(fabs(f[id][i])>=eps) find=true;//find=true表示找到了一个未固定的且第i个未知数系数不为0的行 
        if(id!=i){//换到第i行去,为了好看。 
            for(int j=1;j<=n+1;j++){
                swap(f[id][j],f[i][j]);
            }
        }
        if(find){//找到 
            vis[i]=true;//要用来消其他的行,这一行就固定住,不要动了,要不就乱了 
            for(int j=1;j<=n;j++){//这里从1开始循环,把xi系数非0的行全消一遍 
                if(j==i) continue;
                lb ch=f[j][i]/f[i][i];
                for(int k=1;k<=n+1;k++){
                    f[j][k]=f[j][k]-ch*f[i][k];
                }
            }
        }
    }
    //判断有没有解 
    int wq=0,wj=0;
    for(int i=1;i<=n;i++)
    {
        int j=1;
        while(fabs(f[i][j])<eps&&j<=n+1)j++;
        if(j>n+1)wq=1;//如果这一行全是0,那么这一个未知数是自由元,先把wq设为1,(但是不是无穷取决于会不会之后无解) 
        if(j==n+1)wj=1; //这一行除了等式右边都是0,那么无解,wj设为1 
    }
    if(wj){return -1;}//先判断无解
    if(wq){return 0;}//不是无解且wq为1的话,那么是无穷多组解。 
    
    for(int i=n;i>=1;i--){//倒着推导每一个未知数 
        for(int j=1;j<=n;j++){
            if(i==j) continue;
            f[i][n+1]-=f[i][j]*ans[j];
        }
        ans[i]=f[i][n+1]/f[i][i]+eps;
    }
    return 1;
}
int main()
{
    scanf("%d",&n);lb k;
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n+1;j++){
        scanf("%Lf",&f[i][j]);
        }
    }
    fl=0;
    fl=guass();
    if(fl!=1) {
        printf("%d",fl);return 0;
    }
    for(int i=1;i<=n;i++){
        printf("x%d=%.2Lf\n",i,ans[i]);
    }
    return 0;
}

 

posted @ 2024-08-20 12:17  *Miracle*  阅读(39)  评论(2编辑  收藏  举报