根本没想到可以用高斯消元来做,看了网上大牛的日志才知道,哎!自愧不如!下面正式讲解:
首先一个开关最多只能又一次操作(或者没有操作),则对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; }