【高斯消元】[BZOJ3505]和谐矩阵

题目描述:我们称一个由0和1组成的矩阵是和谐的,当且仅当每个元素都有偶数个相邻的1。一个元素相邻的元素包括它本
身,及他上下左右的4个元素(如果存在)。
给定矩阵的行数和列数,请计算并输出一个和谐的矩阵。注意:所有元素为0的矩阵是不允许的。

输入样例:
4 4

输出:
1 0 1 1
1 0 0 0
0 1 1 1
0 0 1 0

注:本题目Special judge 答案不唯一

题目解析:首先可以发现对于任意 一个点可以影响到他一共有多少个的有附近的四个+自己那么每一个方程把自己设置成1,然后把附近的4个设置成1,然后等于0(因为偶数个1异或得到的值为0)然后得到多个方程之后发现其实答案是多个方程含有多个自由元那么我们另每一行只有一个自由元其他的均为主元=1(因为题目要求矩阵不能全部为0) 那么就可以回带求得一组可行解

下面我用两种方法解决题目:

高斯约当消元法 -》 4000 + ms

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 1600;
int Ma[MAXN+10][MAXN+10], ans[MAXN+10];
bool vis[MAXN+10];
void solve(int n){
    int m = n+1, row, col;
    for(col=1, row=1;col<=n&&row<=n;col++, row++){
        if(!Ma[row][col]){
            for(int j=row+1;j<=n;j++){
                if(Ma[j][col]){
                    swap(Ma[row], Ma[j]);
                    break;
                }
            }
        }
        if(!Ma[row][col]){
            row--;
            continue;
        }
        for(int j=1;j<=n;j++){
            if(j != row && Ma[j][col]){
                for(int k=col;k<=m;k++)
                    Ma[j][k] ^= Ma[row][k];
            }
        }
    }
    row --;
    for(;row;row--){
        int cnt = 0;
        for(int i=row;i<=n;i++){
            if(Ma[row][i]){
                if(vis[i])
                    Ma[row][m] ^= ans[i], Ma[row][i] = 0;
                else cnt++;
            }
        }
        for(int i=row;i<=n;i++){
            if(Ma[row][i]){
                if(--cnt)
                    Ma[row][m] ^= 1, ans[i] = 1;
                else
                    ans[i] = Ma[row][m];
                vis[i] = 1;
            }
        }
    }
}
int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            Ma[(i-1)*m+j][(i-1)*m+j] = 1;
            if(j != 1) Ma[(i-1)*m+j][(i-1)*m+j-1] = 1;
            if(j != m) Ma[(i-1)*m+j][(i-1)*m+j+1] = 1;
            if(i != 1) Ma[(i-1)*m+j][(i-1)*m+j-m] = 1;
            if(i != n) Ma[(i-1)*m+j][(i-1)*m+j+m] = 1;
        }
    }
    //printf("!!!");
    solve(n*m);
    /*for(int i=1;i<=n*m;i++){ for(int j=1;j<=n*m+1;j++) printf("%d ", Ma[i][j]); puts(""); }*/
    for(int i=1;i<=n*m;i++){
        printf(i%m == 0?"%d \n":"%d ", ans[i]);
    }

    return 0;
}

下面是普通高斯消元法 -> 400+ ms
主要是因为我们在后面处理的过程中本就需要回带所以没有必要在前面提前回带
该代码只相差一个循环的变量。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 1600;
int Ma[MAXN+10][MAXN+10], ans[MAXN+10];
bool vis[MAXN+10];
void solve(int n){
    int m = n+1, row, col;
    for(col=1, row=1;col<=n&&row<=n;col++, row++){
        if(!Ma[row][col]){
            for(int j=row+1;j<=n;j++){
                if(Ma[j][col]){
                    swap(Ma[row], Ma[j]);
                    break;
                }
            }
        }
        if(!Ma[row][col]){
            row--;
            continue;
        }
        for(int j=row+1;j<=n;j++){
            if(Ma[j][col]){
                for(int k=col;k<=m;k++)
                    Ma[j][k] ^= Ma[row][k];
            }
        }
    }
    row --;
    for(;row;row--){
        int cnt = 0;
        for(int i=row;i<=n;i++){
            if(Ma[row][i]){
                if(vis[i])
                    Ma[row][m] ^= ans[i], Ma[row][i] = 0;
                else cnt++;
            }
        }
        for(int i=row;i<=n;i++){
            if(Ma[row][i]){
                if(--cnt)
                    Ma[row][m] ^= 1, ans[i] = 1;
                else
                    ans[i] = Ma[row][m];
                vis[i] = 1;
            }
        }
    }
}
int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            Ma[(i-1)*m+j][(i-1)*m+j] = 1;
            if(j != 1) Ma[(i-1)*m+j][(i-1)*m+j-1] = 1;
            if(j != m) Ma[(i-1)*m+j][(i-1)*m+j+1] = 1;
            if(i != 1) Ma[(i-1)*m+j][(i-1)*m+j-m] = 1;
            if(i != n) Ma[(i-1)*m+j][(i-1)*m+j+m] = 1;
        }
    }
    //printf("!!!");
    solve(n*m);
    /*for(int i=1;i<=n*m;i++){ for(int j=1;j<=n*m+1;j++) printf("%d ", Ma[i][j]); puts(""); }*/
    for(int i=1;i<=n*m;i++){
        printf(i%m == 0?"%d \n":"%d ", ans[i]);
    }

    return 0;
}

你可能感兴趣的:(数论,高斯消元,bzoj,CQOI,信息竞赛)