根本没想到可以用高斯消元来做,看了网上大牛的日志才知道,哎!自愧不如!下面正式讲解:
首先一个开关最多只能又一次操作(或者没有操作),则对N个开关的操作可以用一个N维的向量来表示<x1,x2,....,xn>(1>=xi>=0),
用Aij表示对第j个开关操作,i开关会改变状态。Ei,Si分别表示开始时和最终时第i个开关的状态,则可以用如下的数学表达式表示:
E1^S1=(x1*A11)^...^(xn*A1n)
....
En^Sn=(x1*An1)^...^(xn*Ann)
将上述方程组表示成矩阵形式:
E1^S1 A11 A12 ..... A1n x1
... = ........... ^ ....
En^Sn An1 An2 .... Ann xn
下面就是用高斯消元对系数行列式消元!若最后又r行全是0那么有2^r种情况,因为有r个自由变量,意思是有r个开关可以操作也可以不操作,
但是其他的n-r个开关的是否操作是一定的。具体代码如下:
#include<iostream>
#include<vector>
using namespace std;
#define L 38
int a[L][L],s[L],t[L];
int gauss(int n)
{
int ans=0,i=0,j=0,k=0,r=0;
for(i=1,j=1;i<=n && j<=n;j++)
{
k=i; //当前消元到第i行
while(k<=n && !a[k][j]) k++; //直到找到第j列的第一个是1的元素所在的行k
if(a[k][j]) //此处包含k>n的情况
{
for(r=1;r<=n+1;r++) //将第k行换到当前消元的行i
swap(a[i][r],a[k][r]);
for(r=1;r<=n;r++) //如果当前行的第j列为1,除了第i行外的其他n-1行进行消元
{
if(r!=i && a[r][j])
{
for(k=i;k<=n+1;k++)
a[r][k]=a[r][k]^a[i][k];
}
}
i++; //成功消元第i行,消元下面的行
}
}
for(j=i;j<=n;j++) //从第i行开始,如果有增广列不为0,则无解
{
if(a[j][n+1])
return -1;
}
return 1<<(n-i+1); //共有2^(n-i+1)种解
}
int main()
{
int k,n,i=0,j=0,x,y;
cin>>k;
while(k--)
{
memset(a,0,sizeof(a));
cin>>n;
for(i=1;i<=n;i++)
cin>>s[i];
for(i=1;i<=n;i++)
{
cin>>t[i];
a[i][i]=1;
a[i][n+1]=s[i]^t[i];
}
while(true)
{
cin>>x>>y;
if((x+y)==0) break;
a[y][x]=1; //注意此处一定是a[y][x]
}
int ans=gauss(n);
if(ans==-1)
cout<<"Oh,it's impossible~!!"<<endl;
else
cout<<ans<<endl;
}
return 1;
}
浙公网安备 33010602011771号