Poj P1830 开关问题___异或高斯消元

题目大意:

有N个开关,存在着某些联系,当变化一个开关后,与之相关的开关也会变化。
你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。
你的任务是,计算有多少种可以达到指定状态的方法。
(不计开关操作的顺序)

0 < N < 29

分析:

将能影响某个开关的所有开关罗列一下,
可以得到一个异或方程组,
可以通过异或高斯消元来解,
当存在 0 = 1 的情况时则无解
其他情况下,
因为自由元可以取 0 1
所以方程组的解为 2 c n t
c n t 为自由元的数量

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define N 105

using namespace std;

int a[N], T, n;

int main(){
     scanf("%d", &T);
     while (T--) {
            scanf("%d", &n);
            for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
            for (int i = 1; i <= n; i++) {
                 int x;
                 scanf("%d", &x);
                 a[i] = a[i] ^ x;
                 a[i] = a[i] | (1 << i);
            }
            int x, y;
            while (~scanf("%d %d", &x, &y)) {
                   if (!x && !y) break;
                   a[y] = a[y] | (1 << x);
            } 
            int ans = 1;
            for (int i = 1; i <= n; i++) {
                 for (int j = i + 1; j <= n; j++) 
                      if (a[j] > a[i]) swap(a[i], a[j]);
                 if (!a[i]) {
                      ans = 1 << (n - i + 1); 
                      break;
                 }
                 if (a[i] == 1) {
                      ans = 0;
                      break;
                 }
                 for (int k = n; k >= 1; k--) 
                      if (a[i] >> k & 1) {
                          for (int j = 1; j <= n; j++) 
                               if (i != j && (a[j] >> k & 1)) a[j] = a[j] ^ a[i];
                          break;
                      } 
            }
            if (!ans) printf("Oh,it's impossible~!!\n");
                 else printf("%d\n", ans); 
     }
     return 0;
}

猜你喜欢

转载自blog.csdn.net/gx_man_vip/article/details/80368939