zoukankan      html  css  js  c++  java
  • poj 1222 EXTENDED LIGHTS OUT (高斯消元)

    题目链接

    看了好长时间这个题了,也大体弄明白了这个解题的步骤,但是这个方程的过程和为什么这么列还是不太清楚。。嗯,有点无奈

    题意:给一个确定的5*6放入矩阵,每个格子都有一个开关和一盏灯,0表示灯没亮,1表示灯亮着。让你输出一个5*6的矩阵ans[i][j],ans[i][j] = 1表示按下开关,ans[i][j] = 0表示不按开关,使最后所有的灯都熄灭。

    分析:

    30个格子,30个方程,30个未知数。 把每个格子和与它相关联(这题就是它的上下左右)的表示为1,其它表示为0。

    因为题目唯一解,所以模板里没有加多解和无解的情况。

    比较详细的分析可以看这个博客:http://blog.csdn.net/u013081425/article/details/24452153

    假设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 

    初始看成0矩阵

    首先,我们可以把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 的矩阵)就转化为解方程的问题了

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <cmath>
      6 #include <algorithm>
      7 #define LL __int64
      8 const int maxn = 30+10;
      9 using namespace std;
     10 int equ, var, fn;
     11 int a[maxn][maxn], x[maxn];
     12 
     13 int gcd(int a, int b)
     14 {
     15     return b==0?a:gcd(b, a%b);
     16 }
     17 int lcm(int a, int b)
     18 {
     19     return a*b/gcd(a, b);
     20 }
     21 int Gauss()  //记得%2,因为只有0,1两种状态
     22 {
     23     int x_mo;
     24     x_mo = 2;
     25     int i, j, k, max_r, col;
     26     int ta, tb, LCM, tmp;
     27     col = 0;
     28 
     29     for(k = 0; k<equ && col<var; k++, col++)
     30     {
     31         max_r = k;
     32         for(i = k+1; i < equ; i++)
     33             if(abs(a[i][col])>abs(a[max_r][col]))
     34             max_r = i;
     35 
     36         if(max_r != k)
     37             for(j = k; j < var+1; j++)
     38             swap(a[k][j], a[max_r][j]);
     39 
     40         if(a[k][col]==0)
     41         {
     42             k--;
     43             continue;
     44         }
     45         for(i = k+1; i < equ; i++)
     46         {
     47             if(a[i][col] != 0)
     48             {
     49                 LCM = lcm(abs(a[i][col]), abs(a[k][col]));
     50                 ta = LCM/abs(a[i][col]);
     51                 tb= LCM/abs(a[k][col]);
     52                 if(a[i][col]*a[k][col] < 0) tb = -tb;
     53 
     54                 for(j = col; j < var+1; j++)
     55                 a[i][j] = ((a[i][j]*ta - a[k][j]*tb)%x_mo+x_mo)%x_mo;
     56             }
     57         }
     58     }
     59     for(i = var-1; i >= 0; i--)
     60     {
     61         tmp = a[i][var];
     62         for(j = i+1; j < var; j++)
     63         if(a[i][j] != 0)
     64         tmp = ((tmp-a[i][j]*x[j])%x_mo+x_mo)%x_mo;
     65 
     66         if(tmp%a[i][i] != 0) return -2;
     67         while(tmp%a[i][i]!=0) tmp += x_mo;
     68         x[i] = (tmp/a[i][i])%x_mo;
     69     }
     70     return 0;
     71 }
     72 int main()
     73 {
     74     int i, j, t, ca=1;
     75     scanf("%d", &t);
     76     while(t--)
     77     {
     78         equ = 30;
     79         var = 30;
     80         memset(a, 0, sizeof(a));
     81         memset(x, 0, sizeof(x));
     82 
     83         for(i = 0; i < 30; i++)
     84         scanf("%d", &a[i][30]);  //这个就是转置矩阵的最后一列
     85 
     86         for(i = 0; i < 5; i++)
     87         for(j = 0; j < 6; j++)
     88         {
     89             int tmp = i*6+j; //枚举的其实是原矩阵从上往下,从左往右的每一个
     90             a[tmp][tmp] = 1;
     91             if(tmp-6>=0)
     92             a[tmp-6][tmp] = 1; //表示第二个下标能影响第一个下标代表的灯,虽然这个题没影响,但是貌似不能倒过来。
     93             if(tmp+6<30)
     94             a[tmp+6][tmp] = 1;
     95             if(j>=1)
     96             a[tmp-1][tmp] = 1;
     97             if(j<=4)
     98             a[tmp+1][tmp] = 1;
     99         }
    100         fn = Gauss();
    101         printf("PUZZLE #%d
    ", ca++);
    102         for(i = 0; i < 30; i++)
    103         {
    104             if(i%6==5) printf("%d
    ", x[i]);
    105             else printf("%d ", x[i]);
    106         }
    107     }
    108     return 0;
    109 }
  • 相关阅读:
    Ext.Net学习笔记02:Ext.Net用法概览
    Ext.Net学习笔记01:在ASP.NET WebForm中使用Ext.Net
    【转】好的用户界面-界面设计的一些技巧
    发布mvc报错:403.14-Forbidden Web 服务器被配置为不列出此目录的内容
    抢票季:吐槽12306 & 分享抢票经验
    2.5星|《解谜茑屋》:疑似企业公关稿,对话体,信息含量较低
    樊登推荐过的书15本,好书2本半
    一些黑猩猩会使用草药治病,疗效还不错:3.5星|邓巴《人类的算法》
    莫奈塞尚的知名度,主要归功于富豪画家卡耶博特的遗赠:4星|《引爆流行》
    4星|《猎药师》:五千年以来药物研发简史,作者是前一线科学家
  • 原文地址:https://www.cnblogs.com/bfshm/p/3918748.html
Copyright © 2011-2022 走看看