POJ.1830 开关问题
标签(空格分隔): 高斯消元
题意分析
普通的高斯消元求解异或方程组,本题目要求的是输出总共的方案数目,若过没有则输出Oh,it’s impossible~!!。 主要学习一下a矩阵的构造。
首先说一下增广矩阵那部分,也就是常数项一部分。题目给出了每个开关起始状态和末了状态,根据这两个状态我们就可以判断出,具体某个开关是否应该被操作。打个比方,若一开始为1,最后为0,显然这个开关应该被按,一开始为0,最后也为0,那么这个开关就不能被按。可见是否按这个开关,结果应该是stai⨁endi的值。
接着说普通矩阵那部分,首先按开关自身,开关本身应该发生变化,所以有 a[i][i]=1,然而题目中还有给出,按下某个开关x,另外一个开关
然后就可以直接跑高斯消元,最后输出i<<freeOfNum 即可;
代码总览
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define nmax 35
using namespace std;
int a[nmax][nmax];
int x[nmax];
int free_x[nmax];
int sta[nmax],ed[nmax];
int equ,var;
int Gauss(){
int max_r;
int col=0,num = 0;
int k;
for(int i = 0;i<=var;++i) x[i] = free_x[i] = 0;
for(k = 0;k < equ && col < var;k++,col++){
max_r=k;
for(int i=k+1;i<equ;i++){
if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
}
if(max_r!=k){
for(int j=k ;j<var+1;j++) swap(a[k][j],a[max_r][j]);
}
if(a[k][col]==0){
free_x[num++] = col;
k--; continue;
}
for(int i=k+1;i<equ;i++){
if(a[i][col]!=0){
for(int j=col;j<var+1;j++){
a[i][j]^=a[k][j];;
}
}
}
}
for(int i = k;i<equ;++i){
if(a[i][col] != 0) return -1;
}
return var - k;
}
int main(){
//freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&var);
memset(a,0,sizeof a);
equ = var;
for(int i = 0 ;i<var;++i) scanf("%d",&sta[i]);
for(int i = 0 ;i<var;++i) scanf("%d",&ed[i]);
for(int i = 0 ;i<var;++i) a[i][var] = (sta[i] ^ ed[i]);
for(int i = 0 ;i<var;++i) a[i][i] = 1;
int x,y;
while(scanf("%d %d",&x,&y)){
if(x == 0 && y == 0) break;
a[y-1][x-1] = 1;
}
int freeOfNum = Gauss();
if(freeOfNum == -1) printf("Oh,it's impossible~!!\n");
else{
printf("%d\n",1<<freeOfNum);
}
}
return 0;
}