zoukankan      html  css  js  c++  java
  • bzoj 1923

    高斯消元解异或方程组裸题

    首先介绍一下异或方程组:异或方程组是形如$x_1$^$x_2$^...^$x_n$=$1(或0)$($x_iin{0,1}$)的一组方程,我们的目的是求出x_i的值

    乍一看,这好像并不好做,最暴力的方法是$O(2^n)$枚举

    但是有了高斯消元,我们就可以不这么暴力了,而是可以借助高斯消元的思想来解了

    举个例子:

    现在我们有一个方程组长这样:

    $x_1$^$x_3$=$0$

    $x_1$^$x_2$=$0$

    $x_1$^$x_2$^$x_3$=$1$

    (当然,给出的例子是很简单的了)

    但是我们可以借助这种思想:我们首先观察第一个方程:我们希望只有这一个方程中含有$x_1$(这也是高斯消元的思想),这样在其他变量已知的情况下我们就可以求出$x_1$了

    那么根据异或的性质,我们用第一个方程逐个与下面含有$x_1$的方程异或,就可以消去下面所有的$x_1$!

    于是做出来的结果就长这样:

    $x_1$^$x_3$=$0$

    $x_2$^$x_3$=$0$

    $x_2$=$1$

    接下来就是第二个方程:我们要把下面的$x_2$消掉,于是我们的方法同上

    最后结果长这样:

    $x_1$^$x_3$=$0$

    $x_2$^$x_3$=$0$

    $x_3$=$1$

    最后一个方程,发现已经结束了,那么到这里结束,我们向上回代即可

    而回代的原理,也很简单:

    $a$^$b$=$c$可以推出$a$=$c$^$b$(两边异或b即得证)

    所以我们算出$x_3$后将所有有$x_3$的等式两侧异或$x_3$即可,于是方程就变成了这样:

    $x_1$=$1$

    $x_2$=$1$

    $x_3$=$1$

    是不已经解出来了?

    这就是高斯消元解异或方程组的过程及原理

     但是这里会出现一个问题:“自由元”问题

    按道理,给出n个方程组应该是可以解出每个答案的,但是由于异或运算特殊的性质,有时n个方程是难以解出每个值的

    为什么?

    举个例子:

    $x_1$^$x_2$=1

    $x_2$^$x_3$=1

    $x_1$^$x_3$=0

    不难发现,这组方程本身解就不唯一(显然,$(1,0,1)$与$(0,1,0)$都是该方程组的解)

    (如果去探索本质的原因:上面的异或方程在逻辑上等同于以下两个方程:$x_1==x_3$且$x_1!=x_2$,那么考虑取值的方式,不难发现解不是唯一的)

    那么如果用正常的方式来解,最后会变成这种形式:

    $x_1$^$x_2$=1

    $x_2$^$x_3$=1

    这也能看出来,因为丢失了一个方程啊!

    这时我们就称$x_3$是一个自由元,也就是他的值既可以为0又可以为1,此时该异或方程组有很多组解!

    对于自由元问题,目前仅有的办法就是dfs,枚举每个自由元的状态然后回代求解

    但是对于这道题,我们没有必要这么做

    由于对于解不唯一的情况,他只要求输出一句话,所以我们只需在解不唯一的情况下(也就是解了全部方程仍不能得到唯一解时)特判即可

    接下来我们就可以研究如何输出最小方程数了

    首先有个显而易见的事情:至少需要n个方程才能解出所有未知数

    那我们就先拿出n个方程去解,看看是否存在自由元,如果存在的话就再加入一个,直到解出唯一解或用完所有方程为止

    要记录所有自由元的位置

    然后就结束了

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <queue>
    #include <stack>
    using namespace std;
    int n,m;
    int a[2005][1005];
    char ch[2005];
    bool vis[2005];
    int Gauss()
    {
        int ret=0;
        for(int i=1;i<=n;i++)
        {
            int temp=i;
            while(!a[temp][i]&&temp<=n)temp++;
            if(temp==n+1){ret++;continue;}
            vis[i]=1;
            if(i!=temp)for(int j=i;j<=n+1;j++)swap(a[temp][j],a[i][j]);
            for(int j=i+1;j<=n;j++)
            {
                if(!vis[j]&&a[j][i])for(int k=i;k<=n+1;k++)a[j][k]^=a[i][k];
            }
        }
        return ret;
    }
    inline int read()
    {
        int f=1,x=0;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=m;i++)
        {
            scanf("%s",ch+1);
            a[i][n+1]=read();
            for(int j=1;j<=n;j++)a[i][j]=ch[j]-'0';
        }
        int now=n;
        while(Gauss())
        {
            for(int i=1;i<=n;i++)
            {
                if(!vis[i])
                {
                    now++;
                    if(now>m)
                    {
                        printf("Cannot Determine
    ");
                        return 0;
                    }
                    swap(a[now],a[i]);
                }
            }
        }
        for(int i=n;i>=1;i--)for(int j=i-1;j>=1;j--)if(a[j][i])a[j][n+1]^=a[i][n+1];
        printf("%d
    ",now);
        for(int i=1;i<=n;i++)
        {
            if(a[i][n+1])printf("?y7M#
    ");
            else printf("Earth
    ");
        }
        return 0;
    }
  • 相关阅读:
    解决:安装SQl 2008为SQL Server代理服务提供的凭据无效
    jquery 瀑布流效果
    设置swfupload 一次只上传一个文件
    设置swfupload选择文件后不自动上传
    Sublime Text3 & MinGW & LLVM CLang 安装配置CC++编译环境
    在WINDOWS中安装使用SIGPACK(MinGW64+Sublime Text3 &Visual Studio)
    关于ThinkPHP_5 的入口文件
    centos7安装lamp环境
    ThinPHP_5的请求和响应
    MySQL的字段长度和显示宽度
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10815517.html
Copyright © 2011-2022 走看看