题目大意:
给你一些开关的初始状态及终末状态,以及开关之间的关联关系;
要求从初始状态变到终末状态的方法种数;
思路:
如对于开关i,j:代表改变开关i的状态,j的状态也会改变;
由于j的状态是因为i的变化而变化,所以,对于我构造的矩阵a[i][j]
i为行代表方程的编号,即此方程结果对应的开关编号,j代表未知数的系数;开关j随着开关i 变化,那么这里的i和j要相互交换位置!!!!因为行代表的是对应编号开关的状态;
(至于我的前一篇开关问题里面为什么没有交换编号,那是因为他们之间是可以相互影响的)
而这里的影响是单向的;
再就是关于解的个数问题:
联系线性代数的知识:r[A]代表系数矩阵的秩,r[A b]代表增广矩阵的秩;
1,若二者相等则方程组有唯一解;
2,若r[A b]大于r[A],则无解;
3,若r[A b]小于r[A],则有无数组解(由于此题开关未知数只有1和0两种取值,所以其解的个数为2^(自由变元的个数);
至于方程等号右边应该取什么值,那就是此编号代表的开关的状态是否改变,若改变则为1,未改变则为0;
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=30;
int a[maxn+9][maxn+9],n,b[maxn+9];
int Gauss()
{
int i,j,k,l;
for(i=0,j=0; i<n&&j<n; i++,j++)
{
k=i;
for(l=i+1; l<n; l++)
if(a[l][j]>a[k][j]) k=l;
if(k!=i)
for(l=j; l<=n; l++)
swap(a[k][l],a[i][l]);
if(a[i][j]==0)//若寻找到的方程对应未知数的系数为零,那么就考虑此方程的下一个未知数系数,继续停留在此行,而不是接着下一行
{
i--;
continue;
}
for(l=i+1; l<n; l++)
if(a[l][j])//对应系数不为零才需要将其置为零
for(int p=j; p<=n; p++)
a[l][p]^=a[i][p];//由于结果需要对二取模,其实就是抑或运算
}
for(l=i; l<n; l++)//此时代表此方程的系数矩阵全部为零,而等号右边并不为零,那么就是增广矩阵的秩大于系数矩阵,即为无解
if(a[l][n]) return -1;
if(i==n) return 1;//二者相等即有唯一解
else return pow(2.0,n-i);//解的个数为2^(自由变元的个数);
}
int main()
{
int t;
cin>>t;
while(t--)
{
memset(a,0,sizeof a);
cin>>n;
for(int i=0; i<n; i++)
{
cin>>b[i];
}
for(int i=0; i<n; i++)
{
int tmp;
cin>>tmp;
a[i][n]=tmp^b[i];//方程等号右边的结果
a[i][i]=1;
}
do
{
int p,q;
cin>>p>>q;
if(p==0&&q==0) break;
a[q-1][p-1]=1;//注意交换位置
}
while(true);
int r=Gauss();
if(r==-1) cout<<"Oh,it's impossible~!!\n";
else cout<<r<<endl;
}
return 0;
}