poj 1830 开关问题

// 题意:给出n盏灯的初始状态以及最终状态,和改变哪些灯的状态会影响哪些灯的关系,
// 求使初始状态变换到最终状态的方法总数。
// 思路: 把开关是否按下看做一未知元,由每个开关的状态是否需要改变可以列出n个方程,
// 可通过高斯消元解方程组。由于题目求的是方法总数,而每一个自由变元(灯)只有两种状态,即开或关,
// 所以k个自由变元的方法总数就为2^k

#include <iostream>
#include <cstring>
using namespace std;
#define MAXN 29
int equ, var, n;
int a[MAXN][MAXN];
int x[MAXN];

int gcd(int a,int b)
{
if (a==0||b==0)
return max(a,b);
int i=0,j=0;
while (a&1==0)
{
++i;
a=a>>1;
}
while (b&1==0)
{
++j;
b=b>>1;
}
i=min(i,j);
while(1)
{
if(a<b)
swap(a,b);
a-=b;
if(a==0)
return b<<i;
while(a&1==0)
{
a=a>>1;
}
}
}
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
void init()
{
memset(a,0,sizeof(a));
memset(x,0,sizeof(x));
scanf("%d",&n);
var = equ = n;
int st[MAXN], ed[MAXN];
for(int i = 0;i < n; ++i)
scanf("%d",&st[i]);
for(int i = 0;i < n; ++i)
scanf("%d",&ed[i]);
for(int i = 0;i < n; ++i)
{
a[i][i] = 1;
a[i][n] = st[i]^ed[i]; //常数项
}

int ix,iy;
while(scanf("%d%d",&ix,&iy)&&ix)
{
a[iy-1][ix-1] = 1;
}
}
int gauss()
{
int k, col = 0;
for(k = 0;k < equ && col < var; ++k,++col)
{
int max_r = k;
for(int i = k+1;i < equ; ++i)
if(a[i][col] > a[max_r][col])
max_r = i;
if(max_r != k)
{
for(int i = k;i < var+1; ++i)
swap(a[k][i],a[max_r][i]);
}
if(a[k][col] == 0)
{
k --;
continue;
}
for(int i = k+1;i < equ; ++i)
{
if(a[i][col] != 0)
{
int LCM = lcm(a[i][col],a[k][col]);
int ta = LCM/a[i][col], tb = LCM/a[k][col];
if(a[i][col]*a[k][col] < 0)
tb = -tb;
for(int j = col;j < var + 1; ++j)
a[i][j] = ( (a[i][j]*ta)%2 - (a[k][j]*tb)%2 + 2 ) % 2;
}
}
}

// 无解情况
for(int i = k;i < equ; ++i)

if(a[i][col] != 0)
return -1;
// 无穷解,返回自由元个数
if(k < var)

return var - k;
else
return 0; //唯一解:(1<<0)=1
}


int main()
{
int cases;
scanf("%d",&cases);
while(cases--)
{
init();
int ans = gauss();
if(ans == -1)
printf("Oh,it's impossible~!!\n");
else
printf("%d\n",(1<<ans));
}
return 0;
}

posted on 2012-03-17 13:29  sysu_mjc  阅读(141)  评论(0编辑  收藏  举报

导航