线性空间

高斯消元

以前只会贺板子,理解了但不深刻,很快就忘了,现在再看高斯消元,也没有很难理解的。

我们首先第一步枚举要消的元是哪个,然后将其系数置为\(1\),再将剩余方程中这个元的系数消为\(0\),这样辗转反复,我们就可以得到最后一个元的答案,然后逐步带回即可

\(code\)

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const double eps=1e-8;
double a[200][200];
int n;
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 tmp=i;
        for(int j=i+1;j<=n;j++)if(fabs(a[j][i])>fabs(a[tmp][i]))tmp=j;
        if(tmp!=i)swap(a[tmp],a[i]);
        if(fabs(a[i][i])<eps){
            puts("No Solution");
            return 0;
        }
        double lsp=a[i][i];
        for(int j=i;j<=n+1;j++)a[i][j]/=lsp;
        for(int j=i+1;j<=n;j++){
            double op=a[j][i];
            for(int k=i;k<=n+1;k++){
                a[j][k]-=op*a[i][k];
            }
        }
    }
    for(int i=n-1;i>=1;i--){
        for(int k=i+1;k<=n;k++){
            a[i][n+1]-=a[k][n+1]*a[i][k];
        }
    }
    for(int i=1;i<=n;i++)printf("%.2lf\n",a[i][n+1]);
    return 0;
}

高斯约旦消元

就是将高斯消元的过程简略了一下,在消元的情况中也对之前处理过的行消元,这样我们得到的解就可用对角线上的系数与权值相除的方法得到。

\(code\)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const double eps=1e-8;
double a[200][200];
int n;
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 tmp=i;
        for(int j=i+1;j<=n;j++)if(fabs(a[j][i])>fabs(a[tmp][i]))tmp=j;
        if(tmp!=i)swap(a[tmp],a[i]);
        double div=a[i][i];
        if(fabs(div)<eps){
            puts("No Solution");
            return 0;
        }
        for(int j=i;j<=n+1;j++)a[i][j]/=div;
        for(int j=1;j<=n;j++){
            if(j==i)continue;
            div=a[j][i];
            for(int k=i;k<=n+1;k++){
                a[j][k]-=div*a[i][k];
            }
        }
    }
    for(int i=1;i<=n;i++)printf("%.2lf\n",a[i][n+1]/a[i][i]);
    return 0;
}

异或方程组

其实就是将高斯消元的方程组换为了异或方程,即从求解

\[ \begin{cases} a_{1,1}x_1+a_{1,2}x_2+a_{1,3}x_3+...+a_{1,n}x_n=b_1\\ a_{2,1}x_1+a_{2,2}x_2+a_{2,3}x_3+...+a_{1,n}x_n=b_2\\ ...\\ a_{n,1}x_1+a_{n,2}x_2+a_{n,3}x_3+...+a_{n,n}x_n=b_n \end{cases} \]

变为

\[ \begin{cases} a_{1,1}x_1\ xor\ a_{1,2}x_2\ xor\ a_{1,3}x_3\ xor\ ...\ xor\ a_{1,n}x_n=b_1\\ a_{2,1}x_1\ xor\ a_{2,2}x_2\ xor\ a_{2,3}x_3\ xor\ ...\ xor\ a_{1,n}x_n=b_2\\ ...\\ a_{n,1}x_1\ xor\ a_{n,2}x_2\ xor\ a_{n,3}x_3\ xor\ ...\ xor\ a_{n,n}x_n=b_n \end{cases} \]

因为异或是满足结合律和交换律的,所以我们可使用普通高斯消元的方法求解异或方程组,并可用\(bitset\)优化时间。下面的代码是外星千足虫这题的代码,使用的就是\(bitset\)优化高斯约旦消元求解异或方程组。

\(code\)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<bitset>
using namespace std;
int n,m;
bitset<2010>Bit[2010];
char ch[2010];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int s1=0;
        scanf("%s%d",ch+1,&s1);
        for(int j=1;j<=n;j++)Bit[i].set(j,int(ch[j]-'0'));
        Bit[i].set(0,s1);
    }
    int ans=-1;
    for(int i=1;i<=n;i++){
        int tmp=i;
        while(tmp<=m&&!Bit[tmp].test(i))tmp++;
        if(tmp>m){
            puts("Cannot Determine");
            return 0;
        }
        ans=max(ans,tmp);
        if(tmp!=i)swap(Bit[i],Bit[tmp]);
        for(int j=1;j<=m;j++){
            if(i!=j&&Bit[j].test(i)==1)Bit[j]^=Bit[i];
        }
    }
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)printf(Bit[i].test(0)==0?"Earth\n":"?y7M#\n");
    return 0;
}
posted @ 2022-10-26 11:47  hxqasd  阅读(58)  评论(1编辑  收藏  举报