您的位置:首页 > 其它

POJ1222 EXTENDED LIGHTS OUT【高斯消元】

2015-09-09 12:37 330 查看
题目链接:
http://poj.org/problem?id=1222

题目大意:
有一个 5*6 的矩阵,每个位置上都有一盏灯和一个开关,矩阵中 1 表示灯亮,0 表
示灯灭。每当按下一个位置上的开关,这个位置上的灯和周围上、下、左、右共 5
个位置的灯状态都会翻转。问:在这个 5*6 的矩阵中,按下哪些位置上的按钮,可
以把整个矩阵变为全灭状态。输出方案矩阵,矩阵中 1 表示按下开关, 0 表示没有
按下开关。

解题思路:
参考博文:http://blog.csdn.net/shiren_Bod/article/details/5766907 上的解题思
路。把 5*6 个灯组成的矩阵看成是一个 1*30 的向量 a。对于每一个位置上的开关也
构造一个 1*30 的向量,一个开关最多控制 5 盏灯,其中开关改变为 1,开关不改变
为 0,则每个位置上的开关向量中最多有 5 项为 1,其余为 0。这样 30 个位置的开
关向量构成一个 30*30 的开关矩阵 Matrix[][]。用 Matrix[][] 第31列(即Matirx[]
)
的 30*1 向量来存储结果,Matrix[i]
来表示第 I 个开关是否改变。
然后用高斯消元法来求解结果。

AC代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

int Array[50][50],Matrix[50][50];
int Dire[4][2] = {-1,0,1,0,0,-1,0,1};

bool Check(int x,int y)
{
if(x >= 0 && x < 5 && y >= 0 && y < 6)
return true;
return false;
}

void Solve(int N)
{
int row = 0,col = 0;
while(row < N && col < N)
{
int id = row;
for(int i = row+1; i < N; ++i)
{
if(Matrix[i][col] > Matrix[id][col])
id = i;
}
if(Matrix[id][col])
{
for(int i = col; i <= N; ++i)
{
int temp = Matrix[id][i];
Matrix[id][i] = Matrix[row][i];
Matrix[row][i] = temp;
}
for(int i = row+1; i < N; ++i)
{
if(Matrix[i][col])
{
for(int j = col; j <= N; ++j)
Matrix[i][j] ^= Matrix[row][j];
}
}
row++;
}
col++;
}

for(int i = N-2; i >= 0; --i)
{
for(int j = i+1; j < N; ++j)
{
Matrix[i]
^= (Matrix[i][j] && Matrix[j]
);
}
}

for(int i = 0; i < N; ++i)
{
printf("%d ",Matrix[i]
);
if((i+1)%6 == 0)
printf("\n");
}
}

int main()
{
int T, kase = 0;
scanf("%d",&T);
while(T--)
{
memset(Matrix,0,sizeof(Matrix));
for(int i = 0; i < 5; ++i)
{
for(int j = 0; j < 6; ++j)
{
scanf("%d", &Array[i][j]);
if(Array[i][j])
Matrix[i*6+j][30] = 1;
Matrix[i*6+j][i*6+j] = 1;
for(int k = 0; k < 4; ++k)
{
int x = i + Dire[k][0];
int y = j + Dire[k][1];
if(Check(x,y))
{
Matrix[i*6+j][x*6+y] = 1;
}
}
}
}
printf("PUZZLE #%d\n",++kase);
Solve(30);
}

return 0;
}


套用模板AC代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 50;
int Equ,Var;    //  Equ个方程 Var个变元
//增广矩阵行数为Equ,分别为0~Equ-1
//增广矩阵列数为Var+1,分别为0~var
int A[MAXN][MAXN];  //增广矩阵
int X[MAXN];        //解集
bool FreeX[MAXN];   //标记是否是不确定的变元
int FreeNum;

void Debug()
{
for(int i = 0; i < Equ; ++i)
{
for(int j = 0; j < Var+1; ++j)
{
cout << A[i][j] << ' ';
}
cout << endl;
}
}

int GCD(int a,int b)
{
if(b == 0)
return a;
return GCD(b,a%b);
}

int LCM(int a,int b)
{
return a / GCD(a,b) * b;
}

int Gauss()
{
int i,j,k;
int MaxRow; //当前这列绝对值最大的行
int col = 0;    //当前处理的列
int Lcm;
int ta,tb;
int temp;
int FreeXNum;
int FreeIndex;

for(i = 0; i <= Var; ++i)
{
X[i] = 0;
FreeX[i] = true;
}
//转换为阶梯矩阵
for(k = 0; k < Equ && col < Var; ++k,++col)
{   //枚举当前处理的行
//找到第col列元素绝对值最大的那行与第k行交换(为了在除法时减小误差)
MaxRow = k;
for(i = k+1; i < Equ; ++i)
{
if(abs(A[i][col]) > abs(A[MaxRow][col]))
MaxRow = i;
}
if(MaxRow != k) //与第k行交换
{
for(i = k; i < Var+1; ++i)
swap(A[k][i],A[MaxRow][i]);
}
if(A[k][col] == 0)  //说明col列第k行以下全是0了,则处理当前行的下一列
{
k--;
continue;
}
for(i = k+1; i < Equ; ++i)
{   //枚举要删去的行
if(A[i][col])
{
Lcm = LCM(abs(A[i][col]),abs(A[k][col]));
ta = Lcm / abs(A[i][col]);
tb = Lcm / abs(A[k][col]);
if(A[i][col] * A[k][col] < 0)   //异号相加
tb = -tb;
for(j = col; j < Var+1; ++j)
{
A[i][j] = (A[i][j]*ta%2 - A[k][j]*tb%2 + 2) % 2;
}
}
}
}
//Debug();
//1.无解情况:化简得增广矩阵中存在(0,0,…,a)这样的行(a!=0)
for(i = k; i < Equ; ++i)
{
if(A[i][col])
return -1;
}
//2.无穷解情况:在Var*(Var+1)的增广矩阵中出现(0,0,…,0)这样的行
//说明没有形成严格的上三角矩阵,且出现的行数即为自由变元的个数
if(k < Var)
{
for(i = k-1; i >= 0; --i)
{
FreeXNum = 0;
for(j = 0; j < Var; ++j)
{
if(A[i][j] && FreeX[j])
{
FreeXNum++;
FreeIndex = j;
}
}
if(FreeXNum > 1)
continue;
temp = A[i][Var];
for(j = 0; j < Var; ++j)
{
if(A[i][j] && j != FreeIndex)
temp -= A[i][j] * X[j];
}
X[FreeIndex] = temp / A[i][FreeIndex];
FreeX[FreeIndex] = 0;   //该变元是确定的
}
return Var - k;
}
//3.唯一解情况:在Var*(Var+1)的增广矩阵中形成严格的上三角矩阵
for(i = Var-1; i >= 0; --i)
{
temp = A[i][Var] % 2;
for(j = i+1; j < Var; ++j)
{
if(A[i][j])
temp = (temp - A[i][j]*X[j]%2 + 2) % 2;
}
if(temp % A[i][i] != 0)
return -2;
X[i] = temp / A[i][i] % 2;
}
return 0;
}

int main()
{
int T,kase = 0;
scanf("%d",&T);
while(T--)
{
Equ = Var = 30;
memset(A,0,sizeof(A));
for(int i = 0; i < 5; ++i)
{
for(int j = 0; j < 6; ++j)
{
if(i != 0)
A[i*6+j][(i-1)*6+j] = 1;
if(i != 4)
A[i*6+j][(i+1)*6+j] = 1;
if(j != 0)
A[i*6+j][i*6+j-1] = 1;
if(j != 5)
A[i*6+j][i*6+j+1] = 1;
A[i*6+j][i*6+j] = 1;
}
}
for(int i = 0; i < 30; ++i)
scanf("%d",&A[i][30]);
FreeNum = Gauss();
printf("PUZZLE #%d\n",++kase);
for(int i = 0; i < 30; ++i)
{
if(i % 6 != 0)
printf(" ");
printf("%d",X[i]);
if(i % 6 == 5)
printf("\n");
}
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: