[POJ1830]开关问题(高斯消元,异或方程组)

题目链接:http://poj.org/problem?id=1830

题意:中文题面,求的是方案数。

首先可以知道, 如果方案数不止一个的话,说明矩阵行列式值为0,即存在自由变元,由于变量只有两种状态,那么方案数就是2^自由变元数。

从起始状态到终止状态,只需要关心起始和终止哪些状态不一样就行,也就是翻转奇数次。

由于是倒推,所以开关的影响要反过来存。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 const int maxn = 33;
 6 int equ, var;
 7 int a[maxn][maxn];
 8 int x[maxn];
 9 int free_x[maxn];
10 int free_num;
11 
12 int gauss() {
13     int max_r, col, k;
14     free_num = 0;
15     for(k = 0, col = 0; k < equ && col < var; k++, col++) {
16         max_r = k;
17         for(int i = k + 1; i < equ; i++) {
18             if(abs(a[i][col]) > abs(a[max_r][col]))
19                 max_r = i;
20         }
21         if(a[max_r][col] == 0) {
22             k--;
23             free_x[free_num++] = col;
24             continue;
25         }
26         if(max_r != k) {
27             for(int j = col; j < var + 1; j++)
28                 swap(a[k][j], a[max_r][j]);
29         }
30         for(int i = k + 1; i < equ; i++) {
31             if(a[i][col] != 0) {
32                 for(int j = col; j < var + 1; j++) {
33                     a[i][j] ^= a[k][j];
34                 }
35             }
36         }
37     }
38     for(int i = k; i < equ; i++) {
39         if(a[i][col] != 0)
40             return -1;
41     }
42     if(k < var) return var - k;
43     for(int i = var - 1; i >= 0; i--) {
44         x[i] = a[i][var];
45         for(int j = i + 1; j < var; j++) {
46             x[i] ^= (a[i][j] & x[j]);
47         }
48     }
49     return 0;
50 }
51 
52 int main() {
53     // freopen("in", "r", stdin);
54     int T, _ = 1;
55     char wtf[66] = "Oh,it's impossible~!!";
56     scanf("%d", &T);
57     while(T--) {
58         scanf("%d", &var);
59         equ = var;
60         memset(a, 0, sizeof(a));
61         memset(x, 0, sizeof(x));
62         memset(free_x, 0, sizeof(free_x));
63         for(int i = 0; i < var; i++) {
64             scanf("%d", &a[i][var]);
65             a[i][i] = 1;
66         }
67         int u, v;
68         for(int i = 0; i < var; i++) {
69             scanf("%d", &u);
70             a[i][var] ^= u;
71         }
72         while(~scanf("%d%d",&u,&v) && u+v) {
73             a[v-1][u-1] = 1;
74         }
75         int ret = gauss();
76         if(ret == -1) puts(wtf);
77         else printf("%lld\n", (LL)((LL)1 << ret));
78     }
79     return 0;
80 }

 

posted @ 2016-12-06 16:31  Kirai  阅读(151)  评论(0编辑  收藏  举报