高斯消元小结(贴一些模板)

依旧是跟着hihocoder学习高斯消元,以前只是知道,并不会写,现在感觉写起来还是比较简单的,其实就是一个线性代数的知识。(我记得今年好像做到过一道高斯消元的题,比较隐蔽的方程组,然后队友最后想到了,然而并没有时间写完,结束以后也并没有补一下高斯消元)。

高斯消元关键就是一个倒三角形吧,然后判断是无穷解,无解,唯一解的的条件就是矩阵的秩与n(元的个数)的关系:

n元方程组 Ax = b 解的情况和R(A),R(A,b),n有关。

无解: R(A) < R(A,b)

唯一解:R(A) == R(A,b) == n

无穷解:R(A) == R(A,b) < n

具体实现方法可以看程序,(然而我觉得hihocoder的伪代码写得很不错)。

然后是异或方程组,这里有一个很重要的异或公式 a xor b == c 等价于 b == a xor c,其实这里很好理解。

异或方程可以表示为 初始状态 xor (a[i][1] * x[1]) xor (a[i][2] * x[2]) xor ... xor (a[i][n]*x[n]) == c[i] 这个时候可以转化成:(a[i][1] * x[1]) xor (a[i][2] * x[2]) xor ... xor (a[i][n]*x[n]) == c[i] xor 初始状态。搞定

异或方程组的消元是利用了 1^1 == 0来做的,但是这个消元的时候要注意,1^0 == 1,也就是在消元的时候不能呆头呆脑地直接搞,遇到这个a[j][i] == 0了,直接跳过就好了。

下面贴一下模板:

高斯消元:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#define FOR(i,x,y)  for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define ll long long
#define N 550
#define M 1100

using namespace std;

const double eps = 1e-6;

int n,m;
double a[M][N],c[M],b[N],val[N];


bool zero(double x){
    return fabs(x) < eps;
}

void swap(int i,int j){
    FOR(k,1,n+1){
        b[k] = a[i][k];
        a[i][k] = a[j][k];
        a[j][k] = b[k];
    }
    double tem = c[i];
    c[i] = c[j];
    c[j] = tem;
}

int guass(){
    bool manysolution = false;
    FOR(i,1,n+1){
        bool flag = false;
        FOR(j,i,m+1){
            if(!zero(a[j][i])){
                swap(i,j);
                flag = true;
                break;
            }
        }
        if(!flag){
            manysolution = true;
            continue;
        }
        FOR(j,i+1,m+1){
            double tem = a[j][i]/a[i][i];
            FOR(k,i,n+1){
                a[j][k] = a[j][k] - a[i][k]*tem;
            }
            c[j] = c[j] - c[i]*tem;
        }
    }
    FOR(i,1,m+1){
        bool flag = true;
        FOR(j,1,n+1){
            if(!zero(a[i][j])){
                flag = false;
                break;
            }
        }
        if(flag && !zero(c[i])){
            return -1;
        }
    }
    if(manysolution)
        return 1;
    IFOR(i,n,0){
        FOR(j,1,i){
            double tem = a[j][i]/a[i][i];
            FOR(k,1,n+1){
                a[j][k] = a[j][k] - a[i][k]*tem;
            }
            c[j] = c[j] - c[i]*tem;
        }
        val[i] = c[i]/a[i][i];
    }
    return 0;
}

int main()
{
    //freopen("test.in","r",stdin);
    while(~scanf("%d%d",&n,&m)){
        FOR(i,1,m+1){
            FOR(j,1,n+1)
                scanf("%lf",&a[i][j]);
            scanf("%lf",&c[i]);
        }
        int tem = guass();
        if(tem == -1)   printf("No solutions\n");
        else if(tem == 1) printf("Many solutions\n");
        else{
            FOR(i,1,n+1){
                printf("%d\n",(int)(val[i]+eps));
            }
        }
    }
    return 0;
}

异或方程组:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
#define FOR(i,x,y)  for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define N 35

using namespace std;

const double eps = 1e-6;

char str[10];

int a[N][N],c[N],val[N],ans[N];

void init(){
    FOR(i,0,30) c[i] = c[i] ^ 1;
    memset(a,0,sizeof(a));
    FOR(i,0,30){
        int u = i / 6, v = i % 6;
        a[i][i] = 1;
        int nu,nv;
        nu = u-1;nv = v;
        if(nu >= 0 && nu < 5 && nv >= 0 && nv < 6)  a[i][nu*6+nv] = 1;
        nu = u+1;nv = v;
        if(nu >= 0 && nu < 5 && nv >= 0 && nv < 6)  a[i][nu*6+nv] = 1;
        nu = u;nv = v-1;
        if(nu >= 0 && nu < 5 && nv >= 0 && nv < 6)  a[i][nu*6+nv] = 1;
        nu = u;nv = v+1;
        if(nu >= 0 && nu < 5 && nv >= 0 && nv < 6)  a[i][nu*6+nv] = 1;
    }
}

void swap(int i,int j){
    FOR(k,0,30){
        int tem = a[i][k];
        a[i][k] = a[j][k];
        a[j][k] = tem;
    }
    int tem = c[i];
    c[i] = c[j];
    c[j] = tem;
}

int guass(){
    bool manysolutions = false;
    FOR(i,0,30){
        bool flag = false;
        FOR(j,i,30){
            if(a[j][i]){
                swap(i,j);
                flag = true;
                break;
            }
        }
        FOR(j,i+1,30){
            if(!a[j][i]) continue;
            FOR(k,0,30){
                a[j][k] = a[i][k] ^ a[j][k];
            }
            c[j] = c[i] ^ c[j];
        }
        if(!flag){
            manysolutions = true;
        }
    }
    FOR(i,0,30){
        int flag = true;
        FOR(j,0,30){
            if(a[i][j]) flag = false;
        }
        if(flag && c[i])    return -1;
    }
    if(manysolutions)   return 1;
    IFOR(i,29,-1){
        FOR(j,0,i){
            if(!a[j][i]) continue;
            FOR(k,0,30){
                a[j][k] = a[i][k] ^ a[j][k];
            }
            c[j] = c[j] ^ c[i];
        }
        val[i] = c[i];
    }
    return 0;
}

int main()
{
    //freopen("test.in","r",stdin);
    while(~scanf("%s",str)){
        FOR(i,0,6){
            c[i] = str[i] - '0';
        }
        FOR(i,1,5){
            scanf("%s",str);
            FOR(j,0,6){
                c[i*6+j] = str[j] - '0';
            }
        }
        memset(val,0,sizeof(val));
        init();
        guass();
        int cnt = 0;
        FOR(i,0,30){
            if(val[i])  ans[cnt++] = i;
        }
        printf("%d\n",cnt);
        FOR(i,0,cnt){
            printf("%d %d\n",(ans[i]/6)+1,(ans[i]%6)+1);
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值