poj 1830 开关问题 (高斯消元 )

题意:

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

这题是给定N个灯的初始和最终状态,再给定一些关系,这些关系说明按某个开关可能影响其他的灯的开关情况,可以将这种关系视为一种取反的关系。

对于这题我们假设一组数据:

3
0 1 0
1 1 0
1 2
2 3
1 3
3 2
0 0

对于以上的数据,我们用矩阵来表示整个操作的过程和状态 

   0       1

S =   1           E =    1        

   0         0

我们可以很显然的知道,某个等的亮灭情况将体现出各个开关的复合结果,因此我们可以得到这样的方程组,模二加等价于异或操作:

E(a) = xa*A11 ^ xb*A12 ^ xc*A13 ^ S(a);

E(b) = xa*A21 ^ xb*A22 ^ xc*A23 ^ S(b);

E(c) = xa*A31 ^ xb*A32 ^ xc*A33 ^ S(c);

其中S(a)表示初始状态,E(a)表示a号灯最终的情况,xa表示a号开关是否按下,A13表示3号开关是否影响1号灯的亮灭,异或操作体现了操作的具体影响。

将S项移到方程的左边,我们抽象出系数矩阵,然后构造出增广矩阵,然后就是进行高斯消元,高斯消元的意思可以看作是符合一系列两个逻辑关系的情况 下,对变元要求的变换。只不过这里用的全部都是异或操作,最后我们进行秩的判定,如果矩阵的秩和邻接矩阵的秩不相等的话那么就无解,如果相同的话,那么说 明达到理想灯的亮灭情况下至少需要确定的状态的开关数为矩阵的秩。那么解就是剩下开关的任意选择了,即2^X(每个开关对应关或者是开)。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<set>
  7 #include<map>
  8 #include<queue>
  9 #include<vector>
 10 #include<string>
 11 #define Min(a,b) a<b?a:b
 12 #define Max(a,b) a>b?a:b
 13 #define CL(a,num) memset(a,num,sizeof(a));
 14 #define maxn  35
 15 #define eps  1e-6
 16 #define inf 9999999
 17 #define mx 1<<60
 18 using namespace std;
 19 int mat[maxn][maxn] ;
 20 int x[maxn] ;
 21 int free_x[maxn] ;
 22 int s[maxn],e[maxn] ;
 23 
 24 int gcd(int a,int b)
 25 {
 26     int t;
 27     while(b != 0)
 28     {
 29         t = b;
 30         b = a%b;
 31         a = t;
 32     }
 33     return a;
 34 }
 35 int lcm(int a,int b)
 36 {
 37     return (a*b)/gcd(a,b);
 38 }
 39 int  Gauss(int var,int equ)
 40 {
 41     int i,j,k,col;
 42     int max_r;
 43     int ta,tb;
 44     int LCM;
 45     int free_x_num;
 46     int free_index;
 47     int tmp ;
 48 
 49     for(k = 0 , col = 0;k < equ && col < var;k ++,col++)
 50     {
 51         max_r = k;
 52         for(i = k + 1; i < equ ;++i)
 53         {
 54             if(abs(mat[i][col]) > abs(mat[max_r][col]))max_r = i;
 55         }
 56 
 57 
 58 
 59         if(max_r != k)
 60         {
 61             for(i = col; i < var+1;++i)//
 62             {
 63                 swap(mat[k][i],mat[max_r][i]);
 64             }
 65         }
 66         if(mat[k][col] == 0)
 67         {
 68             k--;
 69             continue ;
 70         }
 71 
 72 
 73         for(i = k  + 1; i < equ;i++)
 74         {
 75             if(mat[i][col])
 76             {
 77 
 78                 for(j = col;j < var + 1; j++)
 79                 {
 80 
 81                     mat[i][j] = mat[i][j]^mat[k][j] ;
 82 
 83                 }
 84             }
 85 
 86         }
 87 
 88     }
 89 
 90 
 91     for(i = k; i < equ ;i++)//
 92     {
 93         if(mat[i][col]!= 0return -1 ;
 94     }
 95 
 96     if(k <= var)
 97     {
 98          return var - k ;
 99 
100     }
101 
102 
103      return  0;
104 }
105 int main()
106 {
107     int i,j,num,n,a,b;
108     //freopen("data.txt","r",stdin);
109     int t;
110     scanf("%d",&t);
111     while(t--)
112     {
113         scanf("%d",&n);
114         CL(mat,0);
115         for(i = 0 ; i< n;i++)
116         {
117             scanf("%d",&s[i]);
118         }
119         for(i = 0; i< n;i++)
120         {
121             mat[i][i] = 1;
122             scanf("%d",&e[i]);
123         }
124         for(i = 0 ; i < n;i++)
125           mat[i][n] = s[i]^e[i] ;
126         while(scanf("%d%d",&a,&b),a+b)
127         {
128             mat[b - 1][a - 1] = 1 ;
129 
130         }
131 
132 
133         int ans = Gauss(n,n);
134         if(ans == -1)
135            printf("Oh,it's impossible~!!\n");
136         else printf("%.0f\n",pow(2.0,ans));
137     }
138 
139 }

原文地址:https://www.cnblogs.com/acSzz/p/2661639.html