HDU 3364 Lanterns (高斯消元解开关问题)

来源:互联网 发布:爱知中学滨河 编辑:程序博客网 时间:2024/06/05 01:18

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3364

题意:n盏灯,m个开关控制,给出每个开关控制的灯序号,求要使所以等为某个状态的方法数(每个开关只有2种状态)。

思路:高斯消元求解方程组的解,m个开关的状态为变量,n盏灯的状态为n条方程的解,异或方程。

#include <stdio.h>#include <string.h>#include <algorithm>#include <math.h>#include <stdlib.h>#define INF 0x7fffffff#define MOD 1000000007using namespace std;typedef long long ll;int n, m;int init[55][55], a[55][55], x[55];//int free_x[55], free_num;int Gauss(){    int r, c, k;    //free_num = 0;    for(k = 0, c = 0; k < n && c < m; k++, c++)    {        r = k;        for(int i = k + 1; i < n; i++)        {//找正在处理的第c个变量系数最大的方程            if(abs(a[i][c]) > abs(a[r][c]))                r = i;        }        if(a[r][c] == 0)        {//这个是自由元,free_x[free_num] = c;            k--;            //free_num++;            continue;        }        if(r != k)        {//把前面找到那个方程换到第r行            for(int j = c; j < m + 1; j++)                swap(a[k][j], a[r][j]);        }        for(int i = k + 1; i < n; i++)        {            if(a[i][c] != 0)            {                for(int j = c; j < m + 1; j++)                {//异或消元,相加摸二等价于异或操作                    a[i][j] ^= a[k][j];                }            }        }    }    for(int i = k; i < n; i++)        if(a[i][c]) return -1;    if(k < m) return m - k;    /*for(int i = m - 1; i >= 0; i--)    {        x[i] = a[i][m];        for(int j = i + 1; j < m; j++)            x[i] ^= (a[i][j] && x[j]);    }*/    return 0;}int main(){    #ifdef LOCAL    freopen("data.in", "r", stdin);    #endif    int t, swi, k, q;    scanf("%d", &t);    for(int cas = 1; cas <= t; cas++)    {        scanf("%d%d", &n, &m);        memset(init, 0, sizeof(init));        for(int i = 0; i < m; i++)        {            scanf("%d", &k);            for(int j = 0; j < k; j++)            {                scanf("%d", &swi);                init[swi - 1][i] = 1;            }        }        scanf("%d", &q);        printf("Case %d:\n", cas);        for(int i = 0; i < q; i++)        {            for(int j = 0; j < n; j++)            {                scanf("%d", &a[j][m]);            }            for(int i = 0; i < n; i++)                for(int j = 0; j < m; j++)                    a[i][j] = init[i][j];            int ans = Gauss();            if(ans == -1)                printf("0\n");            else printf("%I64d\n", (ll)1 << ans);        }    }    return 0;}


0 0