POJ 1222 EXTENDED LIGHTS OUT(高斯消元)

举报
Linux猿 发表于 2021/08/05 01:09:25 2021/08/05
【摘要】 题目链接~~~  这道题做的真纠结,这是学习高斯消元的第一题,没想到就……,开始想了很久没想到怎么做,然后看一些题解吧,结果题解也没看懂。主要是不明白为什么那样列方程,为什么有唯一解,搜了很多博客加上考研线代残留的知识终于完全明白了。  题意就不说了(此题需要一些线性代数的知识),我们先解决第一个问题怎样列方程(或者为什么列方程)? 我们可以把 5*6 的初始矩阵看成一...

题目链接~~~

 这道题做的真纠结,这是学习高斯消元的第一题,没想到就……,开始想了很久没想到怎么做,然后看一些题解吧,结果题解也没看懂。主要是不明白为什么那样列方程,为什么有唯一解,搜了很多博客加上考研线代残留的知识终于完全明白了。

 题意就不说了(此题需要一些线性代数的知识),我们先解决第一个问题怎样列方程(或者为什么列方程)? 我们可以把 5*6 的初始矩阵看成一个30 * 1的列向量(为了后面更好的列方程,所以看成列向量)Y(y1 ,y2 ,y3 ……y30) 。然后把每一个开关也看成一个列向量C(k)(向量里总共30个值),那向量里的值是什么呢?如果第 k 个开关被按下影响了哪个灯就把相应位置为1,否则置为0(例如:按第一个开关,1,2,7号灯会有影响,那么C(1) = {1 ,1 ,0 ,0 ,0 ,0 ,1 ,0,后面全为0},其它的开关也这样,那么要是全部的开关关掉,就必须 Y(y1 ,y2……y30) + x1 * C(k1)  + x2 * C(k2) + x3 * C(k3) ……+x30 * C(k30) = (0 ,0 ,0……0) (再次强调等式里的向量都是列向量),这里等式左边需要mod 2,其中等式中的 x1 ,x2 ……x30 为未知数,为0 或 1 ,1 代表操作了此按钮,0代表没操作,然后我们把所有未知数看成一个列向量X(x1 ,x2 ,x3……x30),C(k1) ,C(k2) ……C(k30),也组成一个30*30 的矩阵 A(C(k1) ,C(k2) ,C(k3)……C(k30))(这里Y其实是一个对称向量,Y的转置等于Y),这样等式就变成了 A*X = Y (mod 2) ,这样方程就列出来了。

 然后为什么有唯一解呢?我们可以发现 r(A) = 30,也就是说 A 可逆,因为r(A) = r(A ,Y) = 30 = n (注意 : 如果矩阵不是30 * 30 的这种形式的矩阵,则可能不是唯一解) ,所以方程一定有唯一解。好了下面就可以用高斯消元解方程了。(因为此矩阵 A 为对称矩阵那么代码中完全可以将向量C(k) 组成 A矩阵的时候看成行向量)。

代码:


  
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std ;
  7. const int MX = 30 + 10 ;
  8. int a[MX][MX] ,ans[MX] ;//a数组存增广矩阵,ans存最终答案
  9. int x[] = {-1 ,1 ,0 ,0 ,0} ,y[] = {0 ,0 ,-1 ,1 ,0} ;
  10. void Gauss(int n ,int m){
  11. int max_r ;
  12. int k = 0 ,col = 0 ;
  13. for( ;k < n && col < m ; ++k ,++col){
  14. max_r = k ;
  15. for(int i = k + 1 ;i < n ; ++i)
  16. if(abs(a[max_r][col]) < abs(a[i][col]))
  17. max_r = i ;
  18. if(!a[max_r][col]){
  19. k-- ;
  20. continue ;
  21. }
  22. if(max_r != k){
  23. for(int i = col ;i <= m ; ++i)
  24. swap(a[k][i] ,a[max_r][i]) ;
  25. }
  26. for(int i = k+1 ;i < n ; ++i){
  27. if(a[i][col]){
  28. for(int j = col ; j <= m ; ++j)
  29. a[i][j] = a[i][j]^a[k][j] ;
  30. }
  31. }
  32. }
  33. for(int i = n-1 ; i >= 0 ; --i){
  34. ans[i] = a[i][m] ;
  35. for(int j = i+1 ;j < m ; ++j)
  36. ans[i] = ans[i]^(a[i][j]&&ans[j]) ;
  37. }
  38. }
  39. void Input(int n ,int m){
  40. for(int i = 0 ;i < n ; ++i){
  41. for(int j = 0 ;j < m ; ++j){
  42. int t = i*m + j ;
  43. scanf("%d" ,&a[t][n*m]) ;
  44. for(int k = 0 ;k < 5 ; ++k){
  45. int sx = x[k] + i ;
  46. int sy = y[k] + j ;
  47. int st = sx*m + sy ;
  48. if(sx >= 0 && sx < n && sy >= 0 && sy < m){
  49. a[t][st] = 1 ;
  50. }
  51. }
  52. }
  53. }
  54. }
  55. int main(){
  56. //freopen("input.txt" ,"r" ,stdin) ;
  57. int T ,cse = 1 ;
  58. cin>>T ;
  59. while(T--){
  60. int n = 5 ,m = 6 ;
  61. memset(a ,0 ,sizeof(a)) ;
  62. memset(ans ,0 ,sizeof(ans)) ;
  63. Input(n ,m) ;
  64. Gauss(n*m ,n*m) ;
  65. cout<<"PUZZLE #"<<cse++<<endl ;
  66. for(int i = 0 ;i < n*m ; ++i){
  67. if((i+1)%6 == 0){
  68. printf("%d\n" ,ans[i]) ;
  69. }else printf("%d " ,ans[i]) ;
  70. }
  71. }
  72. return 0 ;
  73. }
博客链接~~

文章来源: blog.csdn.net,作者:Linux猿,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nyist_zxp/article/details/51952330

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。