(模板)poj1681 高斯消元法求异或方程组(无解、唯一解、多解)

题目链接:https://vjudge.net/problem/POJ-1681

题意:类似于poj1222,有n×n的01矩阵,翻转一个点会翻转其上下左右包括自己的点,求最少翻转多少点能使得矩阵全0。

思路:

  同样的可以枚举第一行的状态,这里不说了。

  用高斯消元法来解这道题,每个点的状态表示一个变量,那么有n*n个方程,n*n个变量的方程组,用高斯消元法来解,可能存在无解,唯一解,多解的情况。多解的时候要枚举自由变元的状态。

AC代码:

/*
    poj1681
    开关问题,高斯消元法解异或方程组
    求最少要翻转的开关使得矩阵全0
    存在无解,唯一解,多解的情况
    多解时要枚举自由变元的状态
   */
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
using namespace std;

const int maxn=250;
const int inf=0x3f3f3f3f;
int T,n,equ,var,a[maxn][maxn],x[maxn],free_xx[maxn];
int ans;
char s[20];

void init(){    //初始化
    memset(a,0,sizeof(a));
    for(int i=0;i<n;++i){
        for(int j=0;j<n;++j){
            int t=i*n+j;
            a[t][t]=1;
            if(i>0) a[t][(i-1)*n+j]=1;
            if(i<n-1) a[t][(i+1)*n+j]=1;
            if(j>0) a[t][i*n+j-1]=1;
            if(j<n-1) a[t][i*n+j+1]=1;
        }
    }
}

int Gauss(){
    int r=0,cnt=0;  //cnt表示自由变元个数
    for(int c=0;r<equ&&c<var;++r,++c){
        int Maxr=r;
        for(int i=r+1;i<equ;++i)
            if(abs(a[i][c])>abs(a[Maxr][c]))
                Maxr=i;
        if(Maxr!=r){
            for(int i=c;i<var+1;++i)
                swap(a[Maxr][i],a[r][i]);
        }
        if(!a[r][c]){
            --r;
            free_xx[cnt++]=c;
            continue;
        }
        for(int i=r+1;i<equ;++i){
            if(!a[i][c]) continue;
            for(int j=c;j<var+1;++j)
                a[i][j]^=a[r][j];
        }
    }
    for(int i=r;i<equ;++i)
        if(a[i][var])
            return -1;    //无解
    return var-r;         //返回自由变元的个数,cnt=var-r
}

int solve(int t){
    ans=inf;
    for(int i=0;i<(1<<t);++i){  //枚举自由变元的状态
        int cnt=0;        //要翻转的个数
        memset(x,0,sizeof(x));
        for(int j=0;j<t;++j){
            if((i>>j)&1){
                ++cnt;
                x[free_xx[j]]=1;
            }
        }
        for(int j=var-t-1;j>=0;--j){
            int tmp=a[j][var],tp,ok=1;
            for(int k=j;k<var;++k){
                if(!a[j][k]) continue;
                if(ok){   //找主元
                    ok=0;
                    tp=k;
                }
                else{
                    tmp^=x[k];
                }
            }
            x[tp]=tmp;
            cnt+=x[tp];
        }
        ans=min(ans,cnt);  //取最小
    }
    return ans;
}

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        init();
        equ=var=n*n;
        for(int i=0;i<n;++i){
            scanf("%s",s);
            for(int j=0;j<n;++j)
                if(s[j]==‘y‘) a[i*n+j][n*n]=0;
                else a[i*n+j][n*n]=1;
        }
        int t=Gauss();
        if(t==-1)
            printf("inf\n");
        else
            printf("%d\n",solve(t));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/FrankChen831X/p/11770528.html

时间: 2024-10-14 20:49:41

(模板)poj1681 高斯消元法求异或方程组(无解、唯一解、多解)的相关文章

poj1753 (高斯消元法求异或方程组)

题目链接:http://poj.org/problem?id=1753 题意:经典开关问题,和poj1222一样,进行两次高斯消元即可,只用初始化的时候改一下初始状态.可能存在无解或多解的情况,多解要枚举自由变元的所有状态. AC代码: #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<cstdlib> using namespace s

P3389 【模板】高斯消元法

P3389 [模板]高斯消元法 题目背景 Gauss消元 题目描述 给定一个线性方程组,对其求解 输入输出格式 输入格式: 第一行,一个正整数 nn 第二至 n+1n+1行,每行 n+1n+1 个整数,为a_1, a_2 \cdots a_na1?,a2??an? 和 bb,代表一组方程. 输出格式: 共n行,每行一个数,第 ii行为 x_ixi? (保留2位小数) 如果不存在唯一解,在第一行输出"No Solution". 输入输出样例 输入样例#1: 复制 3 1 3 4 5 1

Painter&#39;s Problem poj1681 高斯消元法

Painter's Problem Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4420   Accepted: 2143 Description There is a square wall which is made of n*n small square bricks. Some bricks are white while some bricks are yellow. Bob is a painter and

题解 P3389 【【模板】高斯消元法】

题解 P3389 [[模板]高斯消元法] 看到大家都没有重载运算符,那我就重载一下运算符给大家娱乐一下 我使用的是高斯-约旦消元法,这种方法是精度最高的(相对地) 一句话解释高斯约旦消元法: 通过加减消元法,依次制定x0,并通过加减消元法消去其他方程的x0的系数.对于这样的系数矩阵我们只进行初等变幻保证了其正确性 看代码吧,主要是希望帮助大家可以学到一些重载的方法 #include<iostream> #include<cstdio> #include<algorithm&g

PHPCMS V9模板中的常用变量、碎片代码详解

前面是变量,后面是调用变量的解释 {pc:content action="position"posid="12" thumb="1" order="id desc"num="10"} 图片新闻 {pc:contentaction="lists" catid="$r[catid]" num="1"thumb="1" order=&

【模板】高斯消元法

传送门 关于高斯消元的具体过程 详见百度经验 模板 #include <cmath> #include <cstdio> #include <iostream> #define N 201 using namespace std; int n; double a[N][N]; //消成上三角 inline void Guass() { int i, j, k; double div; //枚举列 for(j = 1; j <= n; j++) { //找出最大的主

LG3389 【模板】高斯消元法 高斯消元

问题描述 LG3389 题解 高斯消元,是用来解\(n\)元一次方程组的算法,时间复杂度\(O(n^3)\) 这样就构造出了这个方程组的矩阵 目标就是把这个矩阵左边\(n \times n\)消为单位矩阵 \(\mathrm{Code}\) #include<bits/stdc++.h> using namespace std; void read(int &x){ x=0;char ch=1;int fh; while(ch!='-'&&(ch<'0'||ch&

Luogu3389 【模板】高斯消元法

题目传送门 算法分析 高斯消元,是求解\(n\)个\(n\)元\(1\)次方程组的算法,一般情况下时间复杂度为\(O(n^3)\). 我们把这\(n\)个方程组看成一个\(n\times (n+1)\)的矩阵.以样例为例: \[ \left( \begin{matrix} {{x}_{1}} & 3\times {{x}_{2}} & 4\times {{x}_{3}} \ {{x}_{1}} & 4\times {{x}_{2}} & 7\times {{x}_{3}}

luogu 3389 【模板】高斯消元法

#include <bits/stdc++.h> #define N 104 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n; double g[N][N]; void Gauss() { int i,j,k,now; for(i=1;i<=n;++i) { now=i; for(j=i+1;j<=n;++j) if(fabs(g[j][i])>