原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=3364
Lanterns
Problem Description
Alice has received a beautiful present from Bob. The present contains n lanterns and m switches. Each switch controls some lanterns and pushing the switch will change the state of all lanterns it controls from off to on or from on to off. A lantern may be controlled by many switches. At the beginning, all the lanterns are off.
Alice wants to change the state of the lanterns to some specific configurations and she knows that pushing a switch more than once is pointless. Help Alice to find out the number of ways she can achieve the goal. Two ways are different if and only if the sets (including the empty set) of the switches been pushed are different.
Input
The first line contains an integer T (T<=5) indicating the number of test cases.
The first line of each test case contains an integer n (1<=n<=50) and m (1<=m<=50).
Then m lines follow. Each line contains an integer k (k<=n) indicating the number of lanterns this switch controls.
Then k integers follow between 1 and n inclusive indicating the lantern controlled by this switch.
The next line contains an integer Q (1<=Q<=1000) represent the number of queries of this test case.
Q lines follows. Each line contains n integers and the i-th integer indicating that the state (1 for on and 0 for off) of the i-th lantern of this query.
Output
For each test case, print the case number in the first line. Then output one line containing the answer for each query.
Please follow the format of the sample output.
Sample Input
2
3 2
2 1 2
2 1 3
2
0 1 1
1 1 1
3 3
0
0
0
2
0 0 0
1 0 0
Sample Output
Case 1:
1
0
Case 2:
8
0
题目大意
有
n
n
盏灯,个开关,每个开关可以控制多盏灯,每盏灯可以被多盏开关控制。开
始每盏灯都是开闭状态,给定每盏灯的最终状态,问有多少种方案可以到达。
题解
实际上就是个异或版的高斯消元,异或高斯消元和普通高斯消元没有太大差异,只是在消元时将运算从加减乘除替换为异或而已,我们以开关是否按下为未知数,以灯的状态列方程,以样例里第一组数据为例,矩阵如下:
110101011 1 1 0 1 0 1 0 1 1
其中,第一盏灯受1、2号开关控制,而最终状态要求为关闭,所以方程为 x1 xor x2=0 x 1 x o r x 2 = 0 , x1,x2 x 1 , x 2 的取值为1或0,表示开关按或不按。
消元的时候如果对应未知数的系数是1,那么就用异或来消元,0就跳过,具体过程如下:
第一次消元:
1111 1 1 1 1
第二次消元:
0 0
与普通高斯消元相同,当最后结果为0时,方程有解,反之无解。略有不同的是,由于未知数的取值只能是0或1,所以在有自由元的时候,解的个数也是有限的,等于 2自由元个数 2 自 由 元 个 数 。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=55;
bool x[M][M],hh[M][M];
int n,m,q;
void in()
{
int a,b;
memset(x,0,sizeof(x));
memset(hh,0,sizeof(hh));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
scanf("%d",&a);
for(int j=1;j<=a;++j)
scanf("%d",&b),hh[b][i]=1;
}
scanf("%d",&q);
}
void reset()
{
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
x[i][j]=hh[i][j];
}
ll gauss()
{
int pos,cot=0,p=1;
for(int i=1;i<=m;++i)
{
pos=-1;
for(int j=p;j<=n;++j)
if(x[j][i]){pos=j;break;}
if(pos<0){cot++;continue;}
swap(x[p],x[pos]);
for(int j=1;j<=n;++j)
{
if(x[j][i]&&j!=p)
for(int k=i;k<=m+1;++k)
x[j][k]^=x[p][k];
}
p++;
}
for(int i=p;i<=n;++i)
if(x[i][m+1])return 0;
return 1ll<<cot;
}
void ac(int p)
{
int a;
printf("Case %d:\n",p);
for(int i=1;i<=q;++i)
{
reset();
for(int j=1;j<=n;++j)
scanf("%d",&x[j][m+1]);
printf("%lld\n",gauss());
}
}
int main()
{
int T;
scanf("%d",&T);
for(int i=1;i<=T;++i)
in(),ac(i);
return 0;
}
本文介绍了一道算法题“Lanterns”,通过异或高斯消元方法解决灯状态变化的问题。该方法利用矩阵运算原理,以开关控制灯的变化为背景,实现对灯的目标状态配置的计数。
556

被折叠的 条评论
为什么被折叠?



