依旧是跟着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 "); else if(tem == 1) printf("Many solutions "); else{ FOR(i,1,n+1){ printf("%d ",(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 ",cnt); FOR(i,0,cnt){ printf("%d %d ",(ans[i]/6)+1,(ans[i]%6)+1); } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。