题目链接
http://poj.org/problem?id=1830
思路
很好的一道题。。。
对于
n
个开关,我们可以很容易地列出
其中每个 a、x、c 均为0或1, xi=1 表示第 i 个开关按下,
显然对于第
j
个开关的方程而言,
最终我们可以通过高斯消元得到一个上三角变换,而这个上三角下面还有很多系数和常数项全为0的行,这些方程对应的未知数就是自由元。假设有
s
个自由元,那么方程的解的个数就是
但是若存在有某些系数全为0,但是常数项为1的行,那么方程显然是无解的。
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXN 1100
using namespace std;
int start[MAXN],end[MAXN],a[MAXN][MAXN];
int Gauss01(int n) //01高斯消元
{
int freeEle=0; //自由元个数
for(int i=1,t=1;i<=n&&t<=n;i++,t++) //消掉x_j
{
int maxr=i;
for(int j=i;j<=n;j++) //交换行使得第i行第i个元素是所有行里最大的
if(a[j][t]>a[maxr][t])
maxr=j;
for(int j=1;j<=n+1;j++) //交换行
swap(a[i][j],a[maxr][j]);
if(a[i][t]==0)
{
freeEle++;
i--;
continue;
}
for(int j=i+1;j<=n;j++) //消去i+1~n行的第i个元素
{
if(a[j][t]==0) continue; //!!!!!
for(int k=t;k<=n+1;k++)
a[j][k]^=a[i][k]; //!!!!
}
}
for(int i=n-freeEle+1;i<=n;i++)
if(a[i][n+1]!=0) //有自由元的常数项不为0,则无解
return -1;
return freeEle;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
memset(a,0,sizeof(a));
memset(start,0,sizeof(start));
memset(end,0,sizeof(end));
for(int i=1;i<=n;i++)
scanf("%d",&start[i]);
for(int i=1;i<=n;i++)
{
scanf("%d",&end[i]);
a[i][n+1]=start[i]^end[i];
a[i][i]=1;
}
while(1)
{
int x,y; //按下x影响y开关
scanf("%d%d",&x,&y);
if(!x&&!y) break;
a[y][x]=1;
}
int ans=Gauss01(n); //ans=自由 元的个数
if(ans<0) printf("Oh,it's impossible~!!\n"); //操多打了一个换行!!
else printf("%d\n",1<<ans);
}
return 0;
}