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代码:
套用模板AC代码:
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; }
相关文章推荐
- linux下查看网关的命令
- Android中AndroidManifest.xml uses-sdk警告
- 解决Win10 Windows10关键错误 开始菜单和Cortana无法工作问题
- ipvsadm 安装配置
- 【剑指offer】面试题6:重建二叉树
- Second Level Cache for Entity Framework 6.1
- sql事务和锁
- POJ 1724 ROADS(费用最短路:优先队列+BFS)
- 安装RPM套件rpm-build错误解决:NOKEY、elfutils is needed
- 1095. Cars on Campus (30)
- centos 6.6升级自带mysql版本文档
- 使用Charles对手机app网络包进行分析
- hdu 3709 Balanced Number 2010成都区域赛 数位dp
- 整数中1出现的次数(从1到n整数中1出现的次数)(算法)
- 【剑指offer】面试题5:从尾到头打印链表
- BZOJ 2241: [SDOI2011]打地鼠 暴力
- PHP用文件锁模拟进程锁
- 格雷码Java
- JAVA延时
- IOC容器之灵活配置对象属性值一