您的位置:首页 > 其它

POJ1830 开关问题【高斯消元法】

2015-09-14 16:50 337 查看
题目连接:

http://poj.org/problem?id=1830

题目大意:

有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的

时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态

如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最

后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。现

在计算有多少种可以达到指定状态的方法。

解题思路:

对于每个灯有改变或者不改变两种状态,用 1、0 来表示。构造矩阵 A[][],A[i][j] 表示操

作第 i 个开关,第 j 个开关的状态也跟着改变。那么就可以建立 N 个方程组,有开关间

的关系可以确定方程组各变元的系数。N 个开关的开始状态和最终状态的亦或,作为方

程组的常数值,然后用高斯消元法解方程组,求解出是否有解。

无解输出 Oh,it's impossible~!! ,有解计算出变元数目,因为每个变元都有0 和 1两种

可能,所以结果为 1 << ans。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 40;

int Equ,Var;
int A[MAXN][MAXN];
int X[MAXN];
bool FreeX[MAXN];
int FreeNum;

void Debug()
{
for(int i = 0; i < Equ; ++i)
{
for(int j = 0; j < Var+1; ++j)
cout << A[i][j] << ' ';
cout << endl;
}
}

int GCD(int a,int b)
{
if(b == 0)
return a;
return GCD(b,a%b);
}

int LCM(int a,int b)
{
return a / GCD(a,b) * b;
}

int Gauss()
{
int i,j,k;
int MaxRow;
int col = 0;
int Lcm;
int ta,tb;
int temp;
int FreeXNum;
int FreeIndex;

for(k = 0; k < Equ && col < Var; ++k,++col)
{
MaxRow = k;
for(i = k+1; i < Equ; ++i)
{
if(abs(A[i][col]) > abs(A[MaxRow][col]))
MaxRow = i;
}
if(MaxRow != k)
{
for(i = k; i < Var+1; ++i)
swap(A[k][i],A[MaxRow][i]);
}
if(A[k][col] == 0)
{
k--;
continue;
}
for(i = k+1; i < Equ; ++i)
{
if(A[i][col])
{
Lcm = LCM(abs(A[i][col]),abs(A[k][col]));
ta = Lcm / abs(A[i][col]);
tb = Lcm / abs(A[k][col]);
if(A[i][col] * A[k][col] < 0)
tb = -tb;
for(j = col; j < Var+1; ++j)
A[i][j] = (A[i][j]*ta - A[k][j]*tb + 2) % 2;
}
}
}

for(i = k; i < Equ; ++i)
if(A[i][col])
return -1;

if(k < Var)
return Var - k;
for(i = Var-1; i >= 0; --i)
{
temp = A[i][Var] % 2;
for(j = i+1; j < Var; ++j)
if(A[i][j])
temp = (temp - A[i][j]*X[j]%2 + 2) % 2;
if(temp % A[i][i])
return -2;
X[i] = temp / A[i][i] % 2;
}
return 0;
}

void Init(int N)
{
memset(A,0,sizeof(A));
memset(X,0,sizeof(X));
Equ = Var = N;
for(int i = 0; i < N; ++i)
A[i][i] = 1;
}

int Start[MAXN],End[MAXN];

int main()
{
int T,N;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
for(int i = 0; i < N; ++i)
scanf("%d",&Start[i]);
for(int i = 0; i < N; ++i)
scanf("%d",&End[i]);
Init(N);
int u,v;
while(~scanf("%d%d",&u,&v) && (u||v))
{
A[v-1][u-1] = 1;
}
for(int i = 0; i < N; ++i)
A[i]
= (Start[i] - End[i] + 2) % 2;
int ans = Gauss();
if(ans == -1)
printf("Oh,it's impossible~!!\n");
else
printf("%d\n",(1<<ans));
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: