http://poj.org/problem?id=1830
题目大意:有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)
将方程组做成矩阵形式,然后利用三种初等矩阵变换,得到上三角矩阵,最后回代得到解集。
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N = 41; struct Matrix { int n , m; ll a[N][N]; Matrix() {} Matrix(int _n,int _m):n(_n),m(_m){}; void intput() { for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%d",&a[i][j]); } void clear() { memset(a,0,sizeof(a)); } Matrix operator + (const Matrix &b) { Matrix tmp = Matrix(n,m); for(int i=0;i<n;i++) for(int j=0;j<m;j++) tmp.a[i][j] = a[i][j] + b.a[i][j]; return tmp; } Matrix operator - (const Matrix &b) { Matrix tmp = Matrix(n,m); for(int i=0;i<n;i++) for(int j=0;j<m;j++) tmp.a[i][j] = a[i][j] - b.a[i][j]; return tmp; } Matrix operator * (const Matrix &b) { Matrix tmp = Matrix(n,b.m); for(int i=0;i<n;i++) for(int j=0;j<b.m;j++) tmp.a[i][j] = 0; for(int i=0;i<n;i++) for(int k=0;k<m;k++) if(a[i][k]) for(int j=0;j<b.m;j++) tmp.a[i][j] += a[i][k]*b.a[k][j]; return tmp; } }; Matrix operator ^ (Matrix a , int p) { Matrix ret = Matrix(a.n,a.m); for(int i=0;i<a.n;i++) for(int j=0;j<a.m;j++) ret.a[i][j] = (i == j ? 1 : 0); while(p) { if(p%2) ret = ret * a; a = a * a; p /= 2; } return ret; } /* Matrix mi(Matrix a , int p) { Matrix tmp = Matrix(a.n,a.m); for(int i=0;i<a.n;i++) for(int j=0;j<a.m;j++) if(i==j) tmp.a[i][j]=1; else tmp.a[i][j]=0; if(p == 0) return tmp; if(p == 1) return a; if(p % 2) tmp = a; Matrix tt = mi(a , p/2); return tt * tt * tmp; }*/ Matrix A; int Gauss(Matrix A,int r,int c) { int i,j,k,col; for(k=col=0;k<r&&col<c;k++,col++) { int kk = k; for(i=k+1;i<r;i++) if(A.a[i][col]>A.a[kk][col]) kk = i; if(kk != k) for(j=col;j<c+1;j++) swap(A.a[k][j],A.a[kk][j]); if(A.a[k][col] == 0) { k --; continue; } for(i=k+1;i<r;i++) if(A.a[i][col]) for(j=col;j<c+1;j++) A.a[i][j] ^= A.a[k][j]; } for(i=k;i<r;i++) if(A.a[i][col]) return -1; int ans = 1; for(i=0;i<c-k;i++) ans *= 2; return ans; } int main() { int T , n; scanf("%d",&T); while(T--) { scanf("%d",&n); A = Matrix(n+1,n+1); A.clear(); for(int i=0;i<n;i++) scanf("%d",&A.a[i][n]); for(int i=0;i<n;i++) { int tmp; scanf("%d",&tmp); A.a[i][n] ^= tmp; } int x , y; while(scanf("%d%d",&x,&y) && x+y) { x --; y --; A.a[y][x] = 1; } for(int i=0;i<n;i++) A.a[i][i] = 1; int ans = Gauss(A,n,n); if(ans == -1) puts("Oh,it's impossible~!!"); else printf("%d\n" , ans); } return 0; }