题目链接:http://poj.org/problem?id=1830
一,题意:
该题是中文提,题意我就不解释了。
二,解析:
该题我们先的建立一个图,我们以开关为节点,若开关x的变化会影响y开关,则连一条x到y的有向边。
然后我们用邻接矩阵来存储该图。则邻接矩阵中0表示不影响,1表示反转。
例如:样例一, 开始状态为 :begin = [ 0 0 0 ] 最终状态为:end = [ 1 1 1 ] 图的矩阵为:
对角线为1的原因是当你改变某一个节点是除了与他相邻的节点要反转外,其自身也要变。
将矩阵每一列想象为一个开关按下后产生的效果(1表示状态翻转,0表示不变)
即:将每一列最上面想象有一个开关,如图
其中X1,X2,X3 只能取 0或1,因为取2的效果与取0的效果是一样的。
X1=1表示将开关1取反。 X1=0表示不对开关1做操作。
所以我要求的就是 [ x1 x2 x3 ]有多少种情况。
我们令:X=[ x1,x2,x3 ]。关系矩阵 A=[ a1,a2,a3 ]。a1为列向量。
由上面公式可知,b1为开关1的变化次数,b2为开关2变化次数。
而起点 begin 到终点 end 的变化就是 begin^end 即 begin ^ end = b
所以就是解线性方程组(如图):求期解的个数。
解该方程 我们用到高斯消元算法,至于高斯消元就是利用矩阵来解方程组,但是每次
被选取为主元的是一定是最大值。这是为了减少误差。至于利用矩阵来解方程是线性代数
上的内容,,这里就不多说。
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
int b[35];//状态变化数组
int A[35][35];//运算的矩阵
void Gaussian(int N)
{//对N*(N+1)的增广矩阵做初等行变换
for (int r=0,col=0; r<N-1&&col<=N;)
{//行列循环
if (A[r][col]==0)
{//交换两行(找主元)
int i;
for (i=r+1; i<N; i++)
{//从下一行开始找
if (A[i][col] == 1)
{//由于每个格子只有两种状态0,1
for (int j=col; j<=N; j++)
{//行交换
swap(A[i][j], A[r][j]);
}
break;
}
}
if (i==N)
{//如果这一列下面所有的都为0
col++;
continue;
}
}
for (int r2=r+1; r2<N; r2++)
{//用第r行对下面的行消元
if (A[r2][col]==1)
for(int j=col; j<=N; j++)
A[r2][j]^=A[r][j];
}
r++;
col++;
}
}
bool Judge(int *x,int start,int End,int val)
{//判断矩阵第i行是否全为0
for(int i=start; i<End; i++)
if(x[i]!=val)
return false;
return true;
}
int calc(int N)
{//利用行阶梯矩阵解方程
for (int i=0; i<N; i++)
{
if (Judge(A[i],0,N,0))
{//判断系数矩阵第i行是否为0行
for (int j=i; j<N; j++)
{//如果第行为0行则下面全是0
if (A[j][N]==1) //如果有0=d的情况则无解
return -1;
}
return 1<<(N-i);//有解,且有N-i个自由变量
}
}
return 1;
}
int main()
{
int K, N;
scanf("%d",&K);//K组测试数据
for (int i=0; i<K; i++)
{
scanf("%d", &N);//N个开关
memset(b,0,sizeof(b));
memset(A,0,sizeof(A));
for (int j=0; j<N; j++)
scanf("%d",&b[j]);
for (int j=0,tmp; j<N; j++)
{//b是初始和最终的异或,即状态的变化
scanf("%d", &tmp);
b[j]^=tmp;
}
int s,t;
while (scanf("%d%d",&s,&t)!=EOF&&s!=0)
A[t-1][s-1]=1;//存入加转置
for (int j=0; j<N; j++)
{//将b放到最后一列构成增广矩阵
A[j][j]=1;//对角线
A[j][N]=b[j];
}
Gaussian(N);
int res=calc(N);
if (res < 0)
printf("Oh,it's impossible~!!\n");
else
printf("%d\n", res);
}
return 0;
}