POJ 1830 开关问题(高斯消元)题解
思路:乍一看好像和线性代数没什么关系。我们用一个数组B表示第i个位置的灯变了没有,然后假设我用u[i] = 1表示动开关i,mp[i][j] = 1表示动了i之后j也会跟着动,那么第i个开关的最终状态为:u[1]*mp[1][i]^u[2]*mp[2][i]....^u[n]*mp[n][i](或者改为相加 % 2)。显然,前式等于B[i],所以,问题转化为了求u的解个数:MP*U = B。注意MP矩阵的写法。
关于矩阵:
r(A) = r(A,b) 有解
r(A) = r(A,b) = n 有唯一解 (n是未知量的个数,即A的列数)
r(A) = r(A,b) < n 有无穷多解
代码:
#include<queue> #include<cstring> #include<set> #include<map> #include<stack> #include<cmath> #include<vector> #include<cstdio> #include<iostream> #include<algorithm> typedef long long ll; const int maxn = 35 + 10; const int seed = 131; const ll MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; int A[maxn][maxn], B[maxn], n; void Gauss(){ ll R = 0; int row = 1; for(int i = 1; i <= n && row <= n; i++,row++){ int max_r = row; for(int j = row + 1; j <= n; j++){ if(A[j][i] > A[row][i]){ max_r = j;break; } } if(max_r != row){ for(int k = i; k <= n + 1; k++) swap(A[max_r][k], A[row][k]); } if(A[row][i] == 0){ row--; continue; } R++; for(int j = row + 1; j <= n; j++){ if(A[j][i]){ for(int k = i; k <= n + 1; k++) A[j][k] = (A[j][k] - A[row][k] + 2) % 2; } } } for(int i = row; i <= n; i++){ if(A[i][n + 1]){ printf("Oh,it's impossible~!!\n"); return; } } R = n - R; R = 1 << R; printf("%lld\n", R); } int main(){ int T; scanf("%d", &T); while(T--){ scanf("%d", &n); memset(A, 0, sizeof(A)); for(int i = 1; i <= n; i++) scanf("%d", &B[i]); for(int i = 1; i <= n; i++){ int v; scanf("%d", &v); A[i][n + 1] = B[i] ^ v; A[i][i] = 1; } int u, v; while(scanf("%d%d", &u , &v) && u + v){ A[v][u] = 1; } Gauss(); } return 0; }