[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 }
时间: 2024-10-23 04:19:43

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

BZOJ.1923.[SDOI2010]外星千足虫(高斯消元 异或方程组 bitset)

题目链接 m个方程,n个未知量,求解异或方程组. 复杂度比较高,需要借助bitset压位. 感觉自己以前写的(异或)高斯消元是假的..而且黄学长的写法都不需要回代. //1100kb 324ms #include <cstdio> #include <cctype> #include <bitset> #include <algorithm> const int N=1004,M=2004; int n,m; char s[N]; std::bitset&l

UVA11542 Square(高斯消元 异或方程组)

建立方程组消元,结果为2 ^(自由变元的个数) - 1 采用高斯消元求矩阵的秩 #include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<vector> #incl

UVA 11542 Square 高斯消元 异或方程组求解

题目链接:点击打开链接 白书的例题练练手. . . P161 #include <cstdio> #include <iostream> #include <algorithm> #include <math.h> #include <string.h> #include <algorithm> using namespace std; #define ll int #define LL long long const int mod

poj 1830 开关问题 高斯消元

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

poj1830(高斯消元解mod2方程组)

题目链接:http://poj.org/problem?id=1830 题意:中文题诶- 思路:高斯消元解 mod2 方程组 有 n 个变元,根据给出的条件列 n 个方程组,初始状态和终止状态不同的位置对应的方程右边常数项为1,状态相同的位置对于的方程组右边的常数项为0.然后用高斯消元解一下即可.若有唯一解输出1即可,要是存在 k 个变元,则答案为 1 << k, 因为每个变元都有01两种选择嘛- 代码: 1 #include <iostream> 2 #include <s

【POJ1830】开关问题 高斯消元求自由元

#include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/43482357"); } 题意:中文题. 题解: 呃,求自由元个数,然后输出1<<ans:(自由元就是高斯消元消某个变量x时发现以下所有方程当前此位系数都是0) 如果无解输出那个题中给的串. 诶网上代码真不可看,我绝望了决定照自己

POJ1830开关问题——gauss消元

题目链接 分析: 第一个高斯消元题目,操作是异或.奇偶能够用0.1来表示,也就表示成bool类型的方程,操作是异或.和加法没有差别 题目中有两个未知量:每一个开关被按下的次数(0.1).每一个开关的转换次数. 题目仅仅和操作次数的奇偶有关,所以用0.1表示之后,对于每一个开关的转换次数就已经知道了.所以仅仅有一个未知量.能够线性表示.练习使用模板 const int maxn = 40; int a[maxn][maxn]; int gauss(int N, int M) { int r, c,

POJ 1830 开关问题 高斯消元,自由变量个数

http://poj.org/problem?id=1830 如果开关s1操作一次,则会有s1(记住自己也会变).和s1连接的开关都会做一次操作. 那么设矩阵a[i][j]表示按下了开关j,开关i会被操作一次,记得a[i][i] = 1是必须的,因为开关i操作一次,本身肯定会变化一次. 所以有n个开关,就有n条方程, 每个开关的操作次数总和是:a[i][1] + a[i][2] + ... + a[i][n] 那么sum % 2就代表它的状态,需要和(en[i] - be[i] + 2) % 2

bzoj2115 [Wc2011] Xor——高斯消元 &amp; 异或线性基

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2115 异或两次同一段路径的权值,就相当于没有走这段路径: 由此可以得到启发,对于不同的走法,也许只需要找出一些东西,就可以把所有的走法用它们来异或表示出来: 再关注图上的环路,因为从 1 到 n 的不同路径也可以看作是经由 1 和 n 连接的环路,路径上也可能有环路: 发现对于环路的不同走法,就是把路与环的权值异或求最优值,重叠的部分异或了两次相当于不走: 于是问题转化为找出图上的所有环(

POJ - 1222: EXTENDED LIGHTS OUT (开关问题-高斯消元)

pro:给定5*6的灯的状态,如果我们按下一个灯的开关,它和周围4个都会改变状态.求一种合法状态,使得终状态全为关闭: sol:模2意义下的高斯消元. 终于自己手打了一个初级板子. #include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; int a[40][40],ans[40]; int x[5]={0,0,0,1,-1}; int y[5]={0,1,-1,0,0};