• poj1222(枚举or高斯消元解mod2方程组)


    题目链接: http://poj.org/problem?id=1222

    题意: 有一个 5 * 6 的初始矩阵, 1 表示一个亮灯泡, 0 表示一个不亮的灯泡. 对 (i, j) 位置进行一次操作则 (i, j), (i + 1, j), (i - 1, j), (i, j - 1),  (i, j + 1) 位置的灯泡变为原来的相反状态, 输出一种能让所有灯泡都变成不亮状态的操作集合.

    思路:

    1. 可以先枚举第一行的所有操作集合, 2^6 种, 第一行的每一种操作后都得到一个灯泡状态集合, 然后再根据第一行的灯泡状态确定第二行的操作, 若 (1, j) 亮, 则(2, j) 必定要进行一次操作, 若(1, j) 不亮, 则 (2, j) 一定不能进行操作. 依次根据上一行的灯泡状态确定下一行的操作. 然后再对最后一行灯泡的状态进行检查, 若全部不亮则得到一个解.

    代码:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 using namespace std;
     5 
     6 const int N = 5;
     7 const int M = 6;
     8 const int MAXN = 10;
     9 int mp[MAXN][MAXN], sol[MAXN][MAXN];
    10 bool flag = false;
    11 int cas;
    12 
    13 bool check(void){
    14     int gel[MAXN][MAXN];
    15     memcpy(gel, mp, sizeof(mp));
    16     for(int i = 1; i <= M; i++){
    17         if(sol[1][i]){
    18             gel[1][i] ^= 1;
    19             gel[1][i - 1] ^= 1;
    20             gel[1][i + 1] ^= 1;
    21             gel[2][i] ^= 1;
    22             gel[0][i] ^= 1;
    23         }
    24     }
    25     for(int i = 2; i <= N; i++){
    26         for(int j = 1; j <= M; j++){
    27             if(gel[i - 1][j]){
    28                 sol[i][j] = 1;
    29                 gel[i][j] ^= 1;
    30                 gel[i][j - 1] ^= 1;
    31                 gel[i][j + 1] ^= 1;
    32                 gel[i - 1][j] ^= 1;
    33                 gel[i + 1][j] ^= 1;
    34             }else sol[i][j] = 0;
    35         }
    36     }
    37     for(int i = 1; i <= M; i++){
    38         if(gel[N][i]) return false;
    39     }
    40     printf("PUZZLE #%d
    ", cas);
    41     for(int i = 1; i <= N; i++){
    42         for(int j = 1; j <= M; j++){
    43             cout << sol[i][j] << " ";
    44         }
    45         cout << endl;
    46     }
    47     return true;
    48 }
    49 
    50 void dfs(int m){
    51     if(flag) return;
    52     if(m > M){
    53         if(check()) flag = true;
    54         return;
    55     }
    56     sol[1][m] = 1;
    57     dfs(m + 1);
    58     sol[1][m] = 0;
    59     dfs(m + 1);
    60 }
    61 
    62 int main(void){
    63     int t;
    64     cin >> t;
    65     for(cas = 1; cas <= t; cas++){
    66         for(int i = 1; i <= N; i++){
    67             for(int j = 1; j <= M; j++){
    68                 cin >> mp[i][j];
    69             }
    70         }
    71         flag = false;
    72         dfs(1);
    73         if(!flag){
    74             printf("PUZZLE #%d
    ", cas);
    75             cout << "inf" << endl;
    76         }
    77     }
    78     return 0;
    79 }
    View Code

    2. 把 30 个灯泡对应的操作当作 30 个未知数, 其解为 1 或 0, 1 表示对该位置进行一次操作, 0 表示不对该位置进行操作, 每个操作对应一个 1* 30 系数矩阵, 1 表示进行该操作后这个位置的灯泡状态会改变, 0 表示进行该操作后该位置的灯泡状态不会改变. 然后可以列 30 个方程, 常数项为对应位置的灯泡初始状态. 然后直接用高斯消元解一下即可.

    关于高斯消元:

    高斯消元法的原理是:
    若用初等行变换将增广矩阵 化为 ,则AX = B与CX = D是同解方程组。
    所以我们可以用初等行变换把增广矩阵转换为行阶梯阵,然后回代求出方程的解。
    以上是线性代数课的回顾,下面来说说高斯消元法在编程中的应用。
    首先,先介绍程序中高斯消元法的步骤:
    (我们设方程组中方程的个数为equ,变元的个数为var,注意:一般情况下是n个方程,n个变元,但是有些题目就故意让方程数与变元数不同)
    1. 把方程组转换成增广矩阵。
    2. 利用初等行变换来把增广矩阵转换成行阶梯阵。
    枚举k从0到equ – 1,当前处理的列为col(初始为0) ,每次找第k行以下(包括第k行),col列中元素绝对值最大的列与第k行交换。如果col列中的元素全为0,那么则处理col + 1列,k不变。
    3. 转换为行阶梯阵,判断解的情况。
    ① 无解
    当方程中出现(0, 0, …, 0, a)的形式,且a != 0时,说明是无解的。
    ② 唯一解
    条件是k = equ,即行阶梯阵形成了严格的上三角阵。从最后一行开始回代逐一求出解集。
    ③ 无穷解。
    条件是k < equ,即不能形成严格的上三角形,自由变元的个数即为equ – k,但有些题目要求判断哪些变元是不缺定的。
        这里单独介绍下这种解法:
    首先,自由变元有var - k个,即不确定的变元至少有var - k个。我们先把所有的变元视为不确定的。在每个方程中判断不确定变元的个数,如果大于1个,则该方程无法求解。如果只有1个变元,那么该变元即可求出,即为确定变元。

    这段话是从其他博客中摘过来的.

    代码:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 const int MAXN = 3e2;
     7 int equ = 30, var = 30;//有equ个方程,var个变元,增广矩正行数为equ,列数为var+1,从0开始计数
     8 int a[MAXN][MAXN];//增广矩正
     9 int free_x[MAXN];//用来存储自由变元(多解枚举自由变元可以使用)
    10 int free_num;//自由变元个数
    11 int x[MAXN];//解集
    12 
    13 int Gauss(void){//返回-1表示无解,0表示有唯一解,否则返回自由变元个数
    14     int max_r, col, k;
    15     free_num = 0;
    16     for(k = 0, col = 0; k < equ && col < var; k++, col++){
    17         max_r = k;
    18         for(int i = k + 1; i < equ; i++){
    19             if(abs(a[i][col] > abs(a[max_r][col]))) max_r = i;
    20         }
    21         if(a[max_r][col] == 0){
    22             k--;
    23             free_x[free_num++] = col;//这个是变元
    24             continue;
    25         }
    26         if(max_r != k){
    27             for(int j = col; j < var + 1; j++){
    28                 swap(a[k][j], a[max_r][j]);
    29             }
    30         }
    31         for(int i = k + 1; i < equ; i++){
    32             if(a[i][col] != 0){
    33                 for(int j = col; j < var + 1; j++){
    34                     a[i][j] ^= a[k][j];
    35                 }
    36             }
    37         }
    38     }
    39     for(int i = k; i < equ; i++){
    40         if(a[i][col] != 0) return -1;//无解
    41     }
    42     if(k < var) return var - k;//返回自由变元个数
    43     for(int i = var - 1; i >= 0; i--){
    44         x[i] = a[i][var];
    45         for(int j = i + 1; j < var; j++){
    46             x[i] ^= (a[i][j] && x[j]);
    47         }
    48     }
    49     return 0;
    50 }
    51 
    52 int main(void){
    53     int t, n;
    54     cin >> t;
    55     for(int cas = 1; cas <= t; cas++){
    56         for(int i = 0; i < 30; i++){
    57             cin >> a[i][30];
    58             x[i] = 0;//清空数组
    59         }
    60         for(int i = 0; i < 30; i++){//构造增广矩阵
    61             int x1 = i / 6;
    62             int y1 = i % 6;
    63             for(int j = 0; j < 30; j++){
    64                 int x2 = j / 6;
    65                 int y2 = j % 6;
    66                 if(abs(x1 - x2) + abs(y1 - y2) < 2) a[j][i] = 1;
    67                 else a[j][i] = 0;
    68             }
    69         }
    70         Gauss();
    71         cout << "PUZZLE #" << cas << endl;
    72         for(int i = 0; i < 30; i++){
    73             cout << x[i] << " ";
    74             if((i + 1) % 6 == 0) cout << endl;
    75         }
    76     }
    77     return 0;
    78 }
    View Code
  • 相关阅读:
    Json Web Token
    logstash 收集 IIS 日志实践
    Lucene Query In Kibana
    autofac 在.net core 与经典asp.net中的差异
    .net core 集成 autofac.
    向量化
    神经网络学习1
    漏斗限流
    正则化(Regularization)
    简单限流
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/7565405.html
Copyright © 2020-2023  润新知