hdu 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个灯,m个开关,一个开关可能影响多个灯,一开始所有的灯都是灭的,每个开关只能按一次,给你q个目标状态,问达到目标状态有多少种方法。首先输入测试样例数,然后输入n和m,接下来m行,每行首先输入k表示第i个开关影响的灯的数量,接下来输入k个灯的编号。最后输入q以及q个目标状态。

思路:对于n个灯我们可以列出n个方程,有m个未知量,从而构成n*m矩阵对应每个灯的最终状态,构建一个增广矩阵,用高斯消元求出自由变元(开关)的个数res,每个开关只有两种状态开或关,所以答案即为2^res

代码如下

#include <cstdio>  
#include <cstring>  
#include <iostream> 
#include <algorithm>   
#define ll long long
const int MAXN=55;
int matrix[MAXN][MAXN];//保存增广矩阵
int copymatrix[MAXN][MAXN];//副本

using namespace std; 
int Gauss(int a[][MAXN],const int&m,const int &n)//m变元的个数(即开关个数),n方程的个数(即灯的个数)
{
    int res =0,r=0;//res 为自由变元的个数,r为增广矩阵的秩
    for(int i=0;i<m;i++)//处理第i个变元 
    {

        for(int j=r;j<n;j++)//找到第i个变元系数不为0的方程,并放到第r行
        if(a[j][i]){
            for(int k=i;k<=m;k++)
            swap(a[j][k],a[r][k]);  
            break;  
        } 
        if(a[r][i]==0)//第i个变元的系数全为0,说明这个变元是自由变元 
        {
            res++;
            continue;
        }
        for(int j=0;j<n;j++)//消去其他方程的i的变元
            if((j!=r)&&(a[j][i]!=0))
                for(int k=i;k<=m;k++)
                a[j][k]^=a[r][k];
        r++;//矩阵的秩加1 
    }       
    for(int i=r;i<n;i++)//矩阵的秩下面的方程 系数都为0 0*x1+0*x2+...+0*xm恒等于0 ,若!=0则无解
    if(a[i][m])
    return -1;

    return res; 
 } 




int main()
{
    int T,n,m;
    scanf("%d",&T);
    for(int Cas=1;Cas<=T;Cas++)
    {
        scanf("%d %d",&n,&m);
        memset(matrix,0,sizeof(matrix));
        memset(copymatrix,0,sizeof(copymatrix));
        for(int i=0;i<m;i++)
        {
            int k,index;
            scanf("%d",&k);
            for(int j=0;j<k;j++)
            {
                scanf("%d",&index);
                matrix[index-1][i]=1;//第i号开关控制index-1号灯  
            }
        }
        printf("Case %d:\n",Cas);
        int q;
        scanf("%d",&q);
        while(q--)
        {
            for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                copymatrix[i][j]=matrix[i][j];

            for(int i=0;i<n;i++)
            scanf("%d",&copymatrix[i][m]);
            int res=Gauss(copymatrix,m,n); 

            ll sum;
            if(res==-1)
            sum=0;

            else 
            sum=((ll)1)<<res;

            printf("%lld\n",sum);
        }
    }
    return 0;
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值