题意:有n个灯和m个开关,每个开关控制数个灯的状态改变,给出k条询问,问使灯的状态变为询问中的状态有多少种发法。

析:同余高斯消元法,模板题,将每个开关控制每个灯列成行列式,最终状态是结果列,同余高斯消元,如果无解就是0,否则结果就是1<<(自由变元的个数);

代码如下:

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;

const int maxn = 110;
const int mod = 2;

int a[maxn][maxn];//增广矩阵
int b[maxn][maxn];
int x[maxn];//解集
bool free_x[maxn];//标记是否是不确定的变元

int gcd(int a,int b)
{
    return a == 0?b:gcd(b%a,a);
}
int lcm(int a,int b)
{
    return a*b/gcd(a,b);//先除后乘防溢出
}

// 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,但无整数解,
//-1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数)
//有equ个方程,var个变元。增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var.
int Gauss(int equ,int var)
{
    int i,j,k;
    int max_r;// 当前这列绝对值最大的行.
    int col;//当前处理的列
    int ta,tb;
    int LCM;
    int temp;
    int free_x_num;
    int free_index;

//    for(int i=0;i<=var;i++)
//    {
//        x[i]=0;
//        free_x[i]=true;
//    }

    //转换为阶梯阵.
    col=0; // 当前处理的列
    for(k = 0;k < equ && col < var;k++,col++)
    {// 枚举当前处理的行.
// 找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差)
        max_r=k;
        for(i=k+1;i<equ;i++)
        {
            if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
        }
        if(max_r!=k)
        {// 与第k行交换.
            for(j=k;j<var+1;j++) swap(a[k][j],a[max_r][j]);
        }
        if(a[k][col]==0)
        {// 说明该col列第k行以下全是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)%mod+mod)%mod;//如果不是同模取余则改为a[i][j] = (a[i][j]*ta-a[k][j]*tb;
                }
            }
        }
    }
    // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).
    for (i = k; i < equ; i++)
    { // 对于无穷解来说,如果要判断哪些是自由变元,那么初等行变换中的交换就会影响,则要记录交换.
        if (a[i][col]) return -1;
    }
    // 2. 无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.
    // 且出现的行数即为自由变元的个数.
    if (k < var)
    {
        //首先,自由变元有var - k个,即不确定的变元至少有var - k个.
//        for (i = k - 1; i >= 0; i--)
//        {
//            // 第i行一定不会是(0, 0, ..., 0)的情况,因为这样的行是在第k行到第equ行.
//            // 同样,第i行一定不会是(0, 0, ..., a), a != 0的情况,这样的无解的.
//            free_x_num = 0; // 用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元.
//            for (j = 0; j < var; j++)
//            {
//                if (a[i][j] != 0 && free_x[j]) free_x_num++, free_index = j;
//            }
//            if (free_x_num > 1) continue; // 无法求解出确定的变元.
//            // 说明就只有一个不确定的变元free_index,那么可以求解出该变元,且该变元是确定的.
//            temp = a[i][var];
//            for (j = 0; j < var; j++)
//            {
//                if (a[i][j] != 0 && j != free_index) temp -= a[i][j] * x[j];
//            }
//            x[free_index] = temp / a[i][free_index]; // 求出该变元.
//            free_x[free_index] = 0; // 该变元是确定的.
//        }
        return var - k; // 自由变元有var - k个.
    }
    // 3. 唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵.
    // 计算出Xn-1, Xn-2 ... X0.
    //需要解得时候就用下面的循环来解。
//    for (i = var - 1; i >= 0; i--)
//    {
//        temp = a[i][var];
//        for (j = i + 1; j < var; j++)
//        {
//            if (a[i][j] != 0) temp = ((temp - a[i][j]*x[j])%mod+mod)%mod;//temp -= a[i][j] * x[j];
//        }
//        while(temp % a[i][i] != 0) temp+=mod;//如果不是同模取余,则temp % a[i][i] != 0时产生浮点数解
//        x[i] = (temp / a[i][i])%mod;
//         if(x[i]<0)x[i]+=mod;
//    }
    return 0;
}
int main()
{
    int i, j;
    int n,m,var;
    int t,kase = 1;
    scanf("%d",&t);
    while (t--)
    {
        memset(b,0,sizeof(b));
        scanf("%d%d", &n, &var);
        for(int i = 0;i < var;i++)
        {
            int num;
            scanf("%d",&num);
            for(int j = 0;j < num;j++)
            {
                int nn;
                scanf("%d",&nn);
                b[nn-1][i] = 1;
            }
        }
        scanf("%d",&m);
        printf("Case %d:\n",kase++);
        while(m--)
        {
            memcpy(a,b,sizeof(b));
            for(int i = 0;i < n;i++)
            {
                scanf("%d",&a[i][var]);
            }
            int ans = Gauss(n,var);
            if(ans == -1)
                printf("0\n");
            else if(ans == 0)
                printf("1\n");
            else
                printf("%I64d\n",1LL<<ans);
        }
    }
    return 0;
}

HDU 3364 Lanterns (高斯消元)的更多相关文章

  1. HDU 3364 Lanterns 高斯消元

    Lanterns Problem Description   Alice has received a beautiful present from Bob. The present contains ...

  2. HDU 3949 XOR 高斯消元

    题目大意:给定一个数组,求这些数组通过异或能得到的数中的第k小是多少 首先高斯消元求出线性基,然后将k依照二进制拆分就可以 注意当高斯消元结束后若末尾有0则第1小是0 特判一下然后k-- 然后HDU输 ...

  3. hdu 5755(高斯消元——模线性方程组模板)

    PS. 看了大神的题解,发现确实可以用m个未知数的高斯消元做.因为确定了第一行的情况,之后所有行的情况都可以根据第一行推. 这样复杂度直接变成O(m*m*m) 知道了是高斯消元后,其实只要稍加处理,就 ...

  4. HDU 3949 XOR [高斯消元XOR 线性基]

    3949冰上走 题意: 给你 N个数,从中取出若干个进行异或运算 , 求最后所有可以得到的异或结果中的第k小值 N个数高斯消元求出线性基后,设秩为$r$,那么总共可以组成$2^r$中数字(本题不能不选 ...

  5. Time travel HDU - 4418(高斯消元)

    Agent K is one of the greatest agents in a secret organization called Men in Black. Once he needs to ...

  6. hdu 4870 rating(高斯消元求期望)

    Rating Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

  7. hdu 6465 线性变换高斯消元

    http://acm.hdu.edu.cn/showproblem.php?pid=6465 题意 给你三个点,再给你经过线性变换后的三个点,然后q次询问,给你一个点,需要你输出线性变换后的点 题解 ...

  8. HDU 3915 Game (高斯消元)

    题意:有n堆石子,每个人只能从某一堆至少拿走一个,不能拿者败.问事先拿走某些堆的石子,使得先手必败. 析:将石子拆成二进制,未知数为1表示保留该堆石子,为0表示事先拿走该堆石子.最后求自由变元的数目, ...

  9. HDU 4870 Rating(高斯消元 )

    HDU 4870   Rating 这是前几天多校的题目,高了好久突然听旁边的大神推出来说是可以用高斯消元,一直喊着赶快敲模板,对于从来没有接触过高斯消元的我来说根本就是一头雾水,无赖之下这几天做DP ...

随机推荐

  1. BZOJ3028: 食物

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3028 题解:列出母函数乘起来化简之后再展开,用插板法即可. 代码: #include<c ...

  2. 20160202.CCPP体系详解(0012天)

    内容概要:C语言控制语句题库.doc 第三章 控制语句 一.选择题 1. 以下语句中无限循环语句是[B]. A)for(;2&5;); B)while(1,2,3); -> while( ...

  3. Spring AOP简介

    AOP简述 AOP的概念早在上个世纪九十年代初就已经出现了,当时的研究人员通过对面向对象思想局限性的分析研究出了一种新的编程思想来帮助开发者减少代码重复提高开发效率,那就是AOP,Aspect-Ori ...

  4. [原创] Ubuntu Linux 安装Eclipse

    一 安装JDK 1.下载 JDK 7从http://www.oracle.com/technetwork/java/javasebusiness/downloads/选择下载JDK的最新版本 JDK ...

  5. 【转】JavaSript模块规范 - AMD规范与CMD规范介绍

    JavaSript模块化   在了解AMD,CMD规范前,还是需要先来简单地了解下什么是模块化,模块化开发?       模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问题 ...

  6. OpenCV 连接 Android IP摄像头

    0.下载IP摄像头(android软件)并安装 比如这个(图标是一个灰色的摄像头的那个软件) 1.新建cpp文件,编译 #include "opencv2/opencv.hpp" ...

  7. ADO.NET+Access: 3,参数 @departmentName 没有默认值

    ylbtech-Error-ADO.NET+Access: 3,参数 @departmentName 没有默认值. 1.A,错误代码返回顶部  3,参数 @departmentName 没有默认值. ...

  8. 查看linux中swap内存的相关参数

    内容主要来源于:linux的内存回收和交换 各项命令查看的linux环境是:Linux SUSE-33 2.6.32.12-0.7-defaul zone? 内存管理的相关逻辑都是以zone为单位的, ...

  9. cocos2d-x CocoStudio中场景触发器(Trigger)的代码部分和触发器之间的互调

    这节继上一篇触发器扩展,讲一下代码部分的实现. 事件:EventDef.h 只有一个枚举,是对触发器事件的编号 #ifndef__EVENTDEF__ #define__EVENTDEF__ enum ...

  10. scala初学

    起因:新公司的程序用scala,为了不落后,不落伍,跟上时代的浪潮,咱们测试也得学学新东西 适合读者:有java经验的IT人士 scala:所有变量都是对象,所有操作都是方法 1.定义变量:变量:类型 ...