首页 > 其他 > 详细

poj 1222 EXTENDED LIGHTS OUT(高斯消元)

时间:2014-04-25 14:39:24      阅读:595      评论:0      收藏:0      [点我收藏+]

http://poj.org/problem?id=1222


先贴一个链接

http://blog.csdn.net/u013081425/article/details/24248247

枚举第一行的状态,进行试探,当最后一行都为0时,说明该方案可行。


另一种方法是高斯消元。

转载分析:这个游戏的名字叫做Lights Out。一个板子上面有MxN个按钮,按钮也是灯。每次按下一个按钮,这个按钮和它的上下左右相邻按钮将同时切换各自的亮灭状态。给你一个初始状态,请给出一种方法,按某些按钮,使得所有的灯都灭。

这个游戏有一些技巧: 
1、按按钮的顺序可以随便。 
2、任何一个按钮都最多需要按下1次。因为按下第二次刚好抵消第一次,等于没有按。 

这个问题可以转化成数学问题。 
一个灯的布局可以看成一个0、1矩阵。以3x3为例: 
0 1 0 
1 1 0 
0 1 1 
表示一个布局。其中0表示灯灭,1表示灯亮。 
每次按下按钮(POJ1222)或者叫一个宿舍关灯(0998),可以看成在原矩阵上加(模2加,就是按位异或)上一个如下的矩阵: 
0 1 0 
1 1 1 
0 1 0 
上述矩阵中的1表示按下第2行第2列的按钮时,作用的范围。如果按左上角的按钮,就是: 
1 1 0 
1 0 0 
0 0 0 

我们记L为待求解的原始布局矩阵。A(i,j)表示按下第i行第j列的按钮时的作用范围矩阵。在上述例子中, 
L= 
0 1 0 
1 1 0 
0 1 1 

A(1,1)= 
1 1 0 
1 0 0 
0 0 0 

A(2,2)= 
0 1 0 
1 1 1 
0 1 0 

假设x(i,j)表示:想要使得L回到全灭状态,第i行第j列的按钮是否需要按下。0表示不按,1表示按下。那么,这个游戏就转化为如下方程的求解: 
L + x(1,1)*A(1,1) + x(1,2)*A(1,2) + x(1,3)*A(1,3) + x(2,1)*A(2,1) + ... + x(3,3)*A(3,3) = 0 

其中x(i,j)是未知数。方程右边的0表示零矩阵,表示全灭的状态。直观的理解就是:原来的L状态,经过了若干个A(i,j)的变换,最终变成0:全灭状态。 
由于是0、1矩阵,上述方程也可以写成: 
x(1,1)*A(1,1) + x(1,2)*A(1,2) + x(1,3)*A(1,3) + x(2,1)*A(2,1) + ... + x(3,3)*A(3,3) = L 

这是一个矩阵方程。两个矩阵相等,充要条件是矩阵中每个元素都相等。将上述方程展开,便转化成了一个9元1次方程组: 

简单地记做:AA * XX = LL 

这个方程有唯一解: 
x(1,1) x(1,2) x(1,3) 
x(2,1) x(2,2) x(2,3) 
x(3,1) x(3,2) x(3,3) 

1 1 1 
0 0 0 
0 0 1 

也就是说,按下第一行的3个按钮,和右下角的按钮,就

能使L状态变成全灭状态。 
对于固定行列的阵列来说,AA矩阵也是确定的。是否存在解,解是否唯一,只与AA矩阵有关。对于唯一解的情形,只要将LL乘以AA的逆矩阵即可。具体求AA的逆矩阵的方法,可以用高斯消元法。

由于是0、1矩阵,上述方程也可以写成:

将1式两边同时加上一个L矩阵就可以变成
x(1,1)*A(1,1) + x(1,2)*A(1,2) + x(1,3)*A(1,3) + x(2,1)*A(2,1) + ... + x(3,3)*A(3,3) = L

A(1,1)把矩阵 转化为一个列向量,L也转化为一个列向量,

将sigma xi*Ai=Li 对应位置的值相等就可以建立方程组了

X1*A(1,1)1+X2*A(1,2)1+X3*A(1,3)1+…………X30*A(30,30)1=L1;    mod 2

X1*A(1,1)2+X2*A(1,2)2+X3*A(1,3)2+…………X30*A(30,30)2=L2;    mod 2

X1*A(1,1)3+X2*A(1,2)3+X3*A(1,3)3+…………X30*A(30,30)3=L3    mod 2

…….

…….

…….

X1*A(1,1)30+X2*A(1,2)30+X3*A(1,3)30+…………X30*A(30,30)30=L30; mod 2

其中A(i,j)k 表示列向量A中第K个元素

这里的*表示点乘,Xi取(1,0) +表示模2加法,所以在高斯消元的时候可以用^异或运算

首先,我们可以把6*5个灯组成的矩阵看成是一个1*30的向量a 。

然后,对于每一个开关 i ,我们也构造一个1*30的向量d(i),一个开关最多控制5个灯,其中开关状态改变则为1,不改变就为0,这样我们可以把30个开关的向量组成一个30*30的矩阵。

我们在构造一个30*1的向量ans,也就是我们要求的结果,ans[ i ]为1,表示需要按下第 i个开关,0表示不需要。这样ans*d=a(mod 2),(d 是30*30 的矩阵)就转化为解方程的问题了。

至于解方程,就没什么可说的了,就是用线代里面讲的方法就可以了。因为这里要模2,所以可以我们可以直接用计算机的异或运算。


#include <stdio.h>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <math.h>
#include <string.h>
#define LL long long
#define _LL __int64

using namespace std;
const int INF = 0x3f3f3f3f;

int a[32][32];
int equ,var;
int ans[32];

void debug()
{
	for(int i = 0; i < 30; i++)
	{
		for(int j = 0; j <= 30; j++)
			printf("%d ",a[i][j]);
		printf("\n");
	}
}
//因为题目说肯定有解,这里没有判断无解和无穷解的情况
void Gauss()
{
	int i,j,row,col,max_r;
	int ta,tb;

	row = col = 0;

	while(row < 30 && col < 30)
	{
		for(i = row; i < equ; i++)
			if(a[i][col] != 0)
				break;

		if(i != row)
		{
			for(j = col; j < var+1; j++)
				swap(a[row][j], a[i][j]);
		}

		if(a[row][col] == 0)
		{
			col++;
			continue;
		}

		for(i = row+1; i < equ; i++)
		{
			if(a[i][col] == 0)
				continue;
			for(j = col; j < var+1; j++)
				a[i][j] ^= a[row][j];
		}
		row++;
		col++;
	}
	//注意求解的方法
	for(i = var-1; i >= 0; i--)
	{
		ans[i] = a[i][var];

		for(j = i+1; j < var; j++)
			ans[i] ^= (a[i][j] && ans[j]);
	}
}

int main()
{
	int test,i,j;
	int x,y,xx,yy;

	scanf("%d",&test);
	for(int item = 1; item <= test; item++)
	{
		for(i = 0; i < 30; i++)
			scanf("%d",&a[i][30]);

		//形成增广阵
		for(i = 0; i < 30; i++)
		{
			x = i/6;
			y = i%6;
			for(j = 0; j < 30; j++)
			{
				xx = j/6;
				yy = j%6;
				if(abs(x-xx) + abs(y-yy) <= 1)
					a[i][j] = 1;
				else a[i][j] = 0;
			}
		}

		equ = var = 30;

		//debug();
		Gauss();

		printf("PUZZLE #%d\n",item);
		for(i = 0; i < 30; i++)
		{
			printf("%d",ans[i]);
			if(i % 6 == 5)
				printf("\n");
			else printf(" ");
		}
	}

	return 0;
}


poj 1222 EXTENDED LIGHTS OUT(高斯消元),布布扣,bubuko.com

poj 1222 EXTENDED LIGHTS OUT(高斯消元)

原文:http://blog.csdn.net/u013081425/article/details/24452153

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!