您的位置:首页 > 其它

poj 1222 EXTENDED LIGHTS OUT

2012-03-17 09:41 309 查看
/*
题意:对于一个5*6的格子,每个格子表示一个灯,每次按下一个按钮,这个按钮和它的上下左右相邻按钮将同时切换各自的亮灭状态,
给定初始状态,问怎么按才能使所有的灯全灭,0表示灯灭,1表示灯亮
注意到每个灯至多只按一次,而按的顺序不影响结果,题目保证有解,
把[i][j]投影到[i*6+j],数组a,x的下标从0开始,线性方程组如下:

a(0,0) * x0 + a(0,1) * x1 +...+ a(0,29) * x29 = b0 = a(0,30)
a(1,0) * x0 + a(1,1) * x1 +...+ a(1,29) * x29 = b1 = a(1,30)
a(2,0) * x0 + a(2,1) * x1 +...+ a(2,29) * x29 = b2 = a(2,30)
. . .
a(29,0) * x0 + a(29,1) * x1 +...+ a(29,29) * x29 = b29 = a(29,30)

其中 a[i][j]=1 当且仅当按下第 j 个灯会切换第 i 个灯的状态,
令a[i*6+j][30]=b[i*6+j],即a的最后一列表示常数项,a是增广矩阵

*/

#include <iostream>        //高斯消元
#include <cstring>
using namespace std;
#define MAXN 31
int equ = 30, var = 30;        //equ指方程个数,var指未知数的个数,即矩阵的行和列
int a[MAXN][MAXN], x[MAXN];  //a表示增广矩阵和x表示方程组的解,而a的最后一列表示常数项
int gcd(int  a,int  b)
{
if (a==0||b==0)
return  max(a,b);
int  i=0,j=0;
while (a&1==0)
{
++i;
a=a>>1;
}
while (b&1==0)
{
++j;
b=b>>1;
}
i=min(i,j);
while(1)
{
if(a<b)
swap(a,b);
a-=b;
if(a==0)
return b<<i;
while(a&1==0)
{
a=a>>1;
}
}
}
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
void init()        //初始化增广矩阵和方程组的解
{
memset(a,0,sizeof(a));
memset(x,0,sizeof(x));
for(int i = 0;i < 5; ++i)
for(int j = 0;j < 6; ++j)
scanf("%d",&a[i*6+j][30]);    // 由于是0,1矩阵,而目标状态是全0,所以可以把初始状态当作目标状态(常数项)
int move[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
for(int i = 0;i < 5; ++i)    // 系数矩阵a[i][j]为1当且仅当按下第j个灯会切换第i个灯的状态
{
for(int j = 0;j < 6; ++j)
{
a[i*6+j][i*6+j] = 1 ;
for(int k = 0;k < 4; ++k)
{
int tx = i + move[k][0];
int ty = j + move[k][1];
if(!(tx >= 0 && tx < 5 && ty >= 0 && ty < 6))
continue;
a[tx*6+ty][i*6+j] = 1 ;        //按下灯[i][j]会影响到灯[tx][ty]
}
}
}
}
void gauss()    //题目保证有解
{
int col = 0;  //当前处理的列
for(int k = 0;k < equ && col < var;++k,++col)
{
int max_r = k;
for(int i = k+1;i < equ; ++i)
if(a[i][col] > a[max_r][col])
max_r = i;
if(max_r != k)
{
for(int i = k;i < var + 1; ++i)
swap(a[k][i],a[max_r][i]);
}
if(a[k][col] == 0)
{
k--;
continue;
}
for(int i = k+1;i < equ; ++i)
{
if(a[i][col] != 0)
{
int LCM = lcm(a[i][col],a[k][col]);
int ta = LCM/a[i][col], tb = LCM/a[k][col];
if(a[i][col]*a[k][col] < 0)
tb = -tb;
for(int j = col;j < var + 1; ++j)
a[i][j] = ( (a[i][j]*ta)%2 - (a[k][j]*tb)%2  +  2 ) % 2;    //a[i][j]只有0和1两种状态
}
}
}
for(int i = var-1;i >= 0; --i)
{
int tmp = a[i][var] % 2;
for(int j = i+1;j < var; ++j)
if(a[i][j] != 0)
tmp = ( tmp - (a[i][j]*x[j])%2  +  2 ) % 2;
x[i] = (tmp/a[i][i]) % 2;
}
}
int main()
{
int cases;
scanf("%d",&cases);
for(int k=1;k<=cases;++k)
{
init();
gauss();
printf("PUZZLE #%d\n",k);
for(int i = 0;i < 5; ++i)
{
for(int j = 0;j < 6; ++j)
printf("%d ",x[i*6+j]);
printf("\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: