hihoCoder#1196 : 高斯消元·二(开关灯问题)

传送门

高斯消元解异或方程组

小Ho在游戏板上忙碌了30分钟,任然没有办法完成,于是他只好求助于小Hi。

小Ho:小Hi,这次又该怎么办呢?

小Hi:让我们来分析一下吧。

首先对于每一个格子的状态,可能会对它造成影响的是其自身和周围4个格子,这五个格子被按下的总次数也就等于该格子所改变的总次数。

对于任意一个格子,如果这个格子改变了偶数次状态,则等价于没有发生改变。

我们可以将1看作格子亮着,0看作格子暗着,每改变1次就加1,最后格子的状态等于其总数值 MOD 2。

则其运算结果刚好满足异或运算,即每改变一次等于状态值 xor 1。

同样的对于一个格子和它周围的4个格子来说,若格子被按下偶数次,它自身和周围4个格子的状态也等于没有发生改变。所以我们可以知道:任意一个格子至多被按下一次。

假设有数组x[1..30],分别表示这30个格子是否按下1次,若按下则x[i]=1,否则x[i]=0。

则对于1个格子,他最后的状态为:

当前状态 = 初始状态 xor (a[1] * x[1]) xor (a[2] * x[2]) xor ... xor (a[30] * x[30])

其中a[i]表示格子i是否会对当前格子产生影响,若能够则a[i] = 1,否则a[i] = 0

对方程进行变换有:

(a[1] * x[1]) xor (a[2] * x[2]) xor ... xor (a[30] * x[30]) = 当前状态 xor 初始状态

因为我们的目标是要让所有等格子都为亮的状态,故我们需要让 当前状态 = 1,则:

(a[1] * x[1]) xor (a[2] * x[2]) xor ... xor (a[30] * x[30]) = 1 xor 初始状态

不妨设y = 1 xor 初始状态:

(a[1] * x[1]) xor (a[2] * x[2]) xor ... xor (a[30] * x[30]) = y

对于所有的格子,我们可以连立出方程组:

(a[ 1][1] * x[1]) xor (a[ 1][2] * x[2]) xor ... xor (a[ 1][30] * x[30]) = y[ 1]
(a[ 2][1] * x[1]) xor (a[ 2][2] * x[2]) xor ... xor (a[ 2][30] * x[30]) = y[ 2]
                                            ...
(a[30][1] * x[1]) xor (a[30][2] * x[2]) xor ... xor (a[30][30] * x[30]) = y[30]
		

到此,我们的目标就是求出一个x[1..30],使得上面的方程组成立。

小Ho:这个看上去和高斯消元很像啊。

小Hi:没错,这个方程组叫异或方程组,它可以用和高斯消元同样的方法来解决。

其解答过程几乎和高斯消元无异,判定无解和多解的方式也相同。唯一需要注意的是消元过程不再是高斯消元的加减,而是通过xor运算来进行消元。比如消除第j行第i列的1:

a[j][k] = a[j][k] xor a[i][k], y[j] = y[j] xor y[i]

其原理是:

    (a[j][1] * x[1]) xor (a[j][2] * x[2]) xor ... xor (a[j][30] * x[30]) xor (a[i][1] * x[1]) xor (a[i][2] * x[2]) xor ... xor (a[ i][30] * x[30]) = y[j] xor y[i]
<=> ((a[j][1] * x[1]) xor (a[i][1] * x[1])) xor (((a[j][2] * x[2]) xor (a[i][2] * x[2]))) xor ... xor ((a[j][30] * x[30]) xor (a[i][30] * x[30])) = y[j] xor y[i]<=> ((a[j][1] xor a[i][1]) * x[1]) xor ((a[j][2] xor a[i][2]) * x[2]) xor ... ((a[j][30] xor a[i][30]) * x[30]) = y[j] xor y[i]

而且由于给定游戏板是固定的,我们可以知道a[i][j]矩阵一定是固定的,而且通过计算可以知道我们消元得到的上三角矩阵也是固定的,并且在这一次的问题中该上三角矩阵是满秩的,所以其一定存在唯一解。

所以我们一定有办法完成这个游戏。

小Ho:我明白了,我这就去写程序,这奖品我拿定了!

#include <cmath>
#include <cstdio>
#include <iostream>
#define N 35
#define D(x, y) (((x) - 1) * 6 + (y))

using namespace std;

int ans;
int a[N][N];
char s[N][N];

inline void Guass()
{
	int i, j, k, t;
	for(j = 1; j <= 30; j++)
	{
		t = j;
		for(i = j; i <= 30; i++)
			if(a[i][j] > a[t][j])
				t = i;
		if(t != j) swap(a[t], a[j]);
		for(i = j + 1; i <= 30; i++)
			if(a[i][j])
				for(k = j; k <= 31; k++)
					a[i][k] ^= a[j][k];
	}
	for(i = 30; i >= 1; i--)
	{
		for(j = i + 1; j <= 30; j++)
			a[i][31] ^= (a[i][j] * a[j][31]);
		if(a[i][31]) ans++;
	}
}

int main()
{
	int i, j;
	for(i = 1; i <= 5; i++)
	{
		scanf("%s", s[i] + 1);
		for(j = 1; j <= 6; j++)
		{
			a[D(i, j)][D(i, j)] = 1;
			a[D(i, j)][31] = 1 ^ (s[i][j] - ‘0‘);
			if(1 < i && i <= 5) a[D(i - 1, j)][D(i, j)] = a[D(i, j)][D(i - 1, j)] = 1;
			if(1 <= i && i < 5) a[D(i + 1, j)][D(i, j)] = a[D(i, j)][D(i + 1, j)] = 1;
			if(1 < j && j <= 6) a[D(i, j - 1)][D(i, j)] = a[D(i, j)][D(i, j - 1)] = 1;
			if(1 <= j && j < 6) a[D(i, j + 1)][D(i, j)] = a[D(i, j)][D(i, j + 1)] = 1;
		}
	}
	Guass();
	printf("%d\n", ans);
	for(i = 1; i <= 5; i++)
		for(j = 1; j <= 6; j++)
			if(a[D(i, j)][31])
				printf("%d %d\n", i, j);
	return 0;
}

  

时间: 2024-10-11 13:54:57

hihoCoder#1196 : 高斯消元·二(开关灯问题)的相关文章

hihoCoder 1196 高斯消元&#183;二

Description 一个黑白网格,点一次会改变这个以及与其连通的其他方格的颜色,求最少点击次数使得所有全部变成黑色. Sol 高斯消元解异或方程组. 先建立一个方程组. \(x_i\) 表示这个点是否被用过. 因为第二次使用同一个点,这个点的贡献就被消除了,所以每个点只会被用 0/1 次. \(a_{ij}\) 表示 \(j\) 点对 \(i\) 是否有影响,有影响为 1 否则为 0. 最后的一位表示最后的状态^最初的状态. 这样就列出来了 \(n*m\) 个方程组,一共 \(n*m\) 个

[HIHO1196]高斯消元&#183;二(高斯消元、枚举自由变元)

题目链接:http://hihocoder.com/problemset/problem/1196 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef pair<int, int> pii; 5 const int maxn = 230; 6 int equ, var; 7 int a[maxn][maxn]; 8 int x[maxn]; 9 int free_x[maxn]; 10 int free_num

hihocoder #1195 高斯消元一

hihocoder对算法解释得很详细,就复制粘贴来了 首先我们要计算出上三角矩阵,也就是将方程组变为: a[1][1] * x[1] + a[1][2] * x[2] + ... + a[1][n] * x[n] = y'[1] 0 * x[1] + a[2][2] * x[2] + ... + a[2][n] * x[n] = y'[2] 0 * x[1] + 0 * x[2] + ... + a[3][n] * x[n] = y'[3] ... 0 * x[1] + 0 * x[2] + .

HiHoCoder [Offer收割]编程练习赛6 C. 图像算子(高斯消元小数版)

传送门 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在图像处理的技术中,经常会用到算子与图像进行卷积运算,从而达到平滑图像或是查找边界的效 果. 假设原图为 H×W 的矩阵 A,算子矩阵为 D×D 的矩阵 Op ,则处理后的矩阵 B 大小为 (H?D+1)×(W?D+1).其中: B[i][j]=∑(A[i?1+dx][j?1+dy]?Op[dx][dy])|(dx=1..D,dy=1..D),1≤i≤H?D+1,1≤j≤W?D+1 给定矩阵 A 和 B ,以及

BZOJ 1013 JSOI2008 球形空间产生器sphere 高斯消元

题目大意:给定n维空间下的n+1个点,求这n个点所在的球面的球心 曾经尝试了很久的模拟退火0.0 至今仍未AC 0.0 今天挖粪涂墙怒学了高斯消元-- 我们设球心为X(x1,x2,...,xn) 假设有两点A(a1,a2,...,an)和B(b1,b2,...,bn) 那么我们可以得到两个方程 (x1-a1)^2+(x2-a2)^2+...+(xn-an)^2=r^2 (x1-b1)^2+(x2-b2)^2+...+(xn-bn)^2=r^2 这些方程都是二次的,无法套用高斯消元 但是我们可以做

[ACM] POJ 2947 Widget Factory (高斯消元)

Widget Factory Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 4436   Accepted: 1502 Description The widget factory produces several different kinds of widgets. Each widget is carefully built by a skilled widgeteer. The time required to

高斯消元(一)——基础概念和加减消元

如果遇到这种解方程的题目,想把它每个未知数写出公式可不容易,而在不知道解的数据范围的时候,二分枚举什么的和没做没区别,所以这里引入了高斯消元对此进行解答. 高斯消元简直就是为计算机量身打造的解n元一次方程组的利器,虽然在算法竞赛中并不会考像加减消元这种容易的题目,但是这作为它的基础,还是需要讨论一下的. 1.基础概念 高斯消元是指,用第i个式子将它下方的n-i个式子的第i个未知数系数通过加减消元法变为零,然后反过来求解所有未知数的过程. 2.加减消元 为了方便描述,我们将每个式子按照同一个未知数

bzoj 1013 高斯消元

将二维求圆心的方式推广到n维,然后用高斯消元解. 具体来说就是,设圆上的两点A(a1,a2,...,an), B(b1,b2,...,bn) 和 圆心C(c1,c2,...,cn),则 ∑(ai-ci)2 = ∑(bi-ci)2 ∑2*(ai-bi)*ci=∑(ai2-bi2) 总共有n+1个点,有C(n+1,2)个方程,但很多是冗余的,可以用一个点与其它n个点建立上述方程,然后解出来.

ACM学习历程—HDU 3949 XOR(xor高斯消元)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3949 题目大意是给n个数,然后随便取几个数求xor和,求第k小的.(重复不计算) 首先想把所有xor的值都求出来,对于这个规模的n是不可行的. 然后之前有过类似的题,求最大的,有一种方法用到了线性基. 那么线性基能不能表示第k大的呢? 显然,因为线性基可以不重复的表示所有结果.它和原数组是等价的. 对于一个满秩矩阵 100000 010000 001000 000100 000010 000001