异或方程组就是形如这个样子的方程组:
M[0][0]x[0]^M[0][1]x[1]^…^M[0][N-1]x[N-1]=B[0]
M[1][0]x[0]^M[1][1]x[1]^…^M[1][N-1]x[N-1]=B[1]
…
M[N-1][0]x[0]^M[N-1][1]x[1]^…^M[N-1][N-1]x[N-1]=B[N-1]
其中“^”表示异或(XOR, exclusive or),M[i][j]表示第i个式子中x[j]的系数,是1或者0。B[i]是第i个方程右端的常数,是1或者0。
解这种方程可以套用高斯消元法,只须将原来的加减操作替换成异或操作就可以了,两个方程的左边异或之后,它们的公共项就没有了。
具体的操作方法是这样的:对于k=0..N-1,找到一个M[i][k]不为0的行i,把它与第k行交换,用第k行去异或下面所有M[i][j]不为0的行i,消去它们的第k个系数,这样就将原矩阵化成了上三角矩阵;最后一行只有一个未知数,这个未知数就已经求出来了,用它跟上面所有含有这个未知数的方程异或,就小觑了所有的着个未知数,此时倒数第二行也只有一个未知数,它就被求出来了,用这样的方法可以自下而上求出所有未知数。
1770: [Usaco2009 Nov]lights 燈
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 799 Solved: 377
[ Submit][ Status][ Discuss]
Description
貝希和她的閨密們在她們的牛棚中玩遊戲。但是天不從人願,突然,牛棚的電源跳閘了,所有的燈都被關閉了。貝希是一個很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐,痛苦與絕望。她希望您能夠幫幫她,把所有的燈都給重新開起來!她才能繼續快樂地跟她的閨密們繼續玩遊戲! 牛棚中一共有N(1 <= N <= 35)盞燈,編號為1到N。這些燈被置於一個非常複雜的網絡之中。有M(1 <= M <= 595)條很神奇的無向邊,每條邊連接兩盞燈。 每盞燈上面都帶有一個開關。當按下某一盞燈的開關的時候,這盞燈本身,還有所有有邊連向這盞燈的燈的狀態都會被改變。狀態改變指的是:當一盞燈是開著的時候,這盞燈被關掉;當一盞燈是關著的時候,這盞燈被打開。 問最少要按下多少個開關,才能把所有的燈都給重新打開。 數據保證至少有一種按開關的方案,使得所有的燈都被重新打開。
Input
*第一行:兩個空格隔開的整數:N和M。
*第二到第M+1行:每一行有兩個由空格隔開的整數,表示兩盞燈被一條無向邊連接在一起。 沒有一條邊會出現兩次。
Output
第一行:一個單獨的整數,表示要把所有的燈都打開時,最少需要按下的開關的數目。
Sample Input
1 2
1 3
4 2
3 4
2 5
5 3
輸入細節:
一共有五盞燈。燈1、燈4和燈5都連接著燈2和燈3。
Sample Output
輸出細節:
按下在燈1、燈4和燈5上面的開關。
HINT
Source
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
int a[55][55],n,m,as=1<<26,tot,ans[55];;
void gauss()
{
for(int i=1;i<=n;i++)
{
int j=i;
while(j<=n&&!a[j][i])j++;
if(j>n)continue;
if(i!=j)for(int k=1;k<=n+1;k++)swap(a[i][k],a[j][k]);
for(int j=1;j<=n;j++)
if(i!=j&&a[j][i])
for(int k=1;k<=n+1;k++)
a[j][k]^=a[i][k];
}
}
void dfs(int now)
{
if(tot>=as)return;
if(!now)
{
as=min(as,tot);
return;
}
if(a[now][now])
{
int t=a[now][n+1];
for(int i=now+1;i<=n;i++)
if(a[now][i])t^=ans[i];
ans[now]=t;
if(t)tot++;
dfs(now-1);
if(t)tot--;
}
else
{
tot++;ans[now]=1;dfs(now-1);
tot--;ans[now]=0;dfs(now-1);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
a[i][i]=1,a[i][n+1]=1;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[x][y]=a[y][x]=1;
}gauss();
/* for(int i=1;i<=n;i++)
{
for(int j=1;j<=n+1;j++)
printf("%d ",a[i][j]);
printf("\n");
}*/dfs(n);printf("%d\n",as);//while(1);
}