zoukankan      html  css  js  c++  java
  • 【poj1830-开关问题】高斯消元求解异或方程组

    第一道高斯消元题目~

    题目:有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)0<=N<=29

     

    我们用样例来模拟一下:

    我的高斯消元求解异或方程组模版:

     

     1 int gauss()
     2 {
     3     int i,j,k,l;
     4     //j=当前要消第几个元
     5     //i=当前消了几个元+1(n-i+1就是自由元个数),也就是当前j要处理的这个方程将要放在第i行,构成上三角矩阵。
     6     //i、j不等是因为有些元是自由元,不需要消,这些方程放到最后面(维护上三角矩阵)。
     7     for(i=1,j=1;i<=n && j<=n;j++)
     8     {
     9         for(k=j;k<=n;k++) 
    10             if(a[k][j]) break;//先找到一个这个元的系数不为0方程的换到第i行。
    11         if(a[k][j])
    12         {
    13             for(l=1;l<=n+1;l++) swap(a[i][l],a[k][l]);
    14             for(l=1;l<=n;l++)//注意这里从1开始,因为把最后回代的过程合并了
    15             {
    16                 if(l!=i && a[l][j])//如果系数不为0才异或消元
    17                     for(k=1;k<=n+1;k++) 
    18                         a[l][k]^=a[i][k];
    19             }
    20             i++;
    21         }
    22     }        
    23     for(j=i;j<=n;j++)
    24         if(a[j][n+1]) return -1;
    25     return 1<<(n-i+1);
    26 }

     

     

     

     

    说一下解的个数问题:

    对增广矩阵[A b]做初等行变换,化成阶梯形(高斯消元法),如果存在[0,0,…,0,1]的行,就是无解;如果存在r行[0,0,…,0,0],就意味着有r个自由变量,因为这里的变量只取0/1,所以有2r个解;如果不存在[0,0,…,0,*],即把最后一行去掉后不存在全0行,则A为满秩矩阵,则方程组有唯一解。

     

    代码:

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<iostream>
     6 #include<algorithm>
     7 using namespace std;
     8 
     9 const int N=35;
    10 int n,bit[N],a[N][N];
    11 
    12 void output()
    13 {
    14     for(int i=1;i<=n;i++)
    15     {
    16         for(int j=1;j<=n+1;j++) 
    17             printf("%d ",a[i][j]);
    18         printf("
    ");
    19     }
    20     printf("
    ");
    21 }
    22 
    23 int gauss()
    24 {
    25     int i,j,k,l;
    26     //j=当前要消第几个元
    27     //i=当前消了几个元+1(n-i+1就是自由元个数),也就是当前j要处理的这个方程将要放在第i行,构成上三角矩阵。
    28     //i、j不等是因为有些元是自由元,不需要消,这些方程放到最后面(维护上三角矩阵)。
    29     for(i=1,j=1;i<=n && j<=n;j++)
    30     {
    31         for(k=j;k<=n;k++) 
    32             if(a[k][j]) break;//先找到一个这个元的系数不为0方程的换到第i行。
    33         if(a[k][j])
    34         {
    35             for(l=1;l<=n+1;l++) swap(a[i][l],a[k][l]);
    36             for(l=1;l<=n;l++)//注意这里从1开始,因为把最后回代的过程合并了
    37             {
    38                 if(l!=i && a[l][j])//如果系数不为0才异或消元
    39                     for(k=1;k<=n+1;k++) 
    40                         a[l][k]^=a[i][k];
    41             }
    42             i++;
    43         }
    44     }        
    45     for(j=i;j<=n;j++)
    46         if(a[j][n+1]) return -1;
    47     return 1<<(n-i+1);
    48 }
    49 
    50 int main()
    51 {
    52     int T,x,y;
    53     scanf("%d",&T);
    54     while(T--)
    55     {
    56         scanf("%d",&n);
    57         memset(a,0,sizeof(a));
    58         for(int i=1;i<=n;i++) scanf("%d",&a[i][n+1]);
    59         for(int i=1;i<=n;i++)
    60         {
    61             scanf("%d",&x);
    62             a[i][n+1]^=x;
    63         }
    64         while(1)
    65         {
    66             scanf("%d%d",&x,&y);
    67             if(!x && !y) break;
    68             a[y][x]=1;
    69         }
    70         for(int i=1;i<=n;i++) a[i][i]=1;
    71         int ans=gauss();
    72         if(ans==-1) printf("Oh,it's impossible~!!
    ");
    73         else printf("%d
    ",ans);
    74     }
    75     return 0;
    76 }
  • 相关阅读:
    linux less命令用法
    Spark-RDD 模型 以及运行原理
    Spark 架构原理介绍 以及 job、task、stag 概念
    Kafka 基本概念以及框架介绍
    负载均衡- TCP/ IP 基础知识
    JAVA多线程和并发基础面试题
    Java并发使用--线程池
    Java基础--并发编程
    事务实现原则(一) 事务的改变以及JDBC事务的设计
    Spark RDD Transformation和Action
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/6029059.html
Copyright © 2011-2022 走看看