zoukankan      html  css  js  c++  java
  • 洛谷

    为什么可以跑n立方,我也不知道,反正就是可以。
    模2意义的,据说每一行可以存一个bitset,会比用bool更快(快32倍?)。

    本题告诉我们一个道理:
    高斯消元之后,每个变量的含义不变(虽然交换了两行,但是实际上那个位置的向量还是表示那个单元),不需要复原。
    每个变量要前往的目标状态不一样。注意非自由变量要用新的右边来确定值。
    并不是所有的自由变量都在右下角,有可能有完全空的列。
    也可以在给每行赋值秩的同时指定该列是秩为第几的列,0表示空列。
    可以在消元的同时对自由变量进行赋值,非自由变量立刻由他决定。但是感觉很扯。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    int n,m,r;
    
    inline int antii(int id) {
        int res=((id+m-1)/m);
        return res;
    }
    
    inline int antij(int id) {
        int res=id%m;
        if(res==0)
            res=m;
        return res;
    }
    
    inline int id(int,int);
    
    bool tx[1800]= {};
    bool allzero[1800]= {};
    bool outtm[50][50]= {};
    
    bool out() {
        int have1=0;
        for(int id=1; id<=n*m; id++) {
            outtm[antii(id)][antij(id)]=tx[id];
        }
    
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++) {
                if(outtm[i][j]^outtm[i-1][j]^outtm[i+1][j]^outtm[i][j-1]^outtm[i][j+1]) {
                    return false;
                }
                if(outtm[i][j])
                    have1=1;
            }
        }
    
        if(!have1)
            return false;
    
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++)
                printf("%d%c",(int)outtm[i][j]," 
    "[j==m]);
        }
    
        return true;
    
        //高斯消元后,每个变量的目标已经改变了,不需要复原!!!
    }
    
    
    namespace Gauss_Jordan_Elimination {
        const int MAXN=1800;
        const int MAXM=1800;
        bool a[MAXN][MAXM+1];
        bool ans[MAXN];
    
    
        //返回增广矩阵的秩,-1表示无解
        int gauss_jordan(int n,int m) {
    
            int r=0;
            for(int i=1; i<=m; i++) {
                //当前是第i列
                int mx=-1;
                //从当前秩的下一行开始往下数
                for(int j=r+1; j<=n; j++)
                    if(a[j][i]) {
                        mx=j;
                        break;
                    }
                if(mx==-1) {
                    //该列全0,被跳过
                    continue;
                }
                r++;
                //增加一个线性基,当前秩增加
                if(mx!=r) {
                    //需要交换
                    for(int j=1; j<=m+1; j++)
                        //m+1表示增广矩阵
                        swap(a[r][j],a[mx][j]);
                    //交换行
                }
    
                for(int j=1; j<=n; j++) {
                    //枚举每一行
                    if(j!=r&&a[j][i]) {
                        //消去除了r以外的其他行
                        //该行系数是当前列的tmp倍
                        for(int k=i; k<=m+1; k++) {
                            //把当前列对应行位置扩大tmp倍,然后用每个元素减去,由高斯约当的过程,左边的绝对是0
                            a[j][k]^=a[r][k];
                        }
                    }
                }
            }
    
            return r;
        }
    }
    
    using namespace Gauss_Jordan_Elimination;
    
    
    inline int id(int i,int j) {
        if(i>=1&&i<=n&&j>=1&&j<=m)
            return (i-1)*m+j;
        else
            return 0;
    }
    
    int dx[4]= {-1,1,0,0};
    int dy[4]= {0,0,-1,1};
    
    void dfs(int x,bool have1) {
        if(x==0) {
            if(have1) {
                if(out()) {
                    exit(0);
                }
            }
            return;
        }
        if(allzero[x]) {
            tx[x]=1;
            dfs(x-1,1);
            tx[x]=0;
            dfs(x-1,have1);
        } else {
            bool v=a[x][n*m+1];
            for(int i=x+1; i<=n*m; i++) {
                v^=a[x][i]&tx[i];
            }
            tx[x]=v;
            dfs(x-1,have1|v);
        }
    }
    
    int main() {
        scanf("%d%d",&n,&m);
    
        {
            {
                memset(a,0,sizeof(a));
                for(int i=1; i<=n; i++) {
                    for(int j=1; j<=m; j++) {
                        int tid=id(i,j);
                        a[tid][tid]=1;
                        for(int k=0; k<4; k++) {
                            int ttid=id(i+dx[k],j+dy[k]);
                            if(ttid) {
                                a[tid][ttid]=1;
                            }
                        }
                    }
                }
    
    
                r=gauss_jordan(n*m,n*m);
    
                for(int i=1; i<=n*m; i++) {
                    allzero[i]=1;
                    for(int j=1; j<=n*m; j++) {
                        if(a[i][j]) {
                            allzero[i]=0;
                            break;
                        }
                    }
                }
    
                dfs(n*m,0);
            }
        }
    
    }
    
    
  • 相关阅读:
    vue 基础补充
    正则
    vue 指令
    函数式编程FP 初探
    .? ?? es2020
    vue alfont scss
    网络安全靶场通关指南
    Java 程序设计——站内短信系统
    Java 程序设计——登录系统
    动态规划法解找零钱问题
  • 原文地址:https://www.cnblogs.com/Yinku/p/10773297.html
Copyright © 2011-2022 走看看