题目链接:http://poj.org/problem?id=1753

题意:一个 4*4 的棋盘,初始时上面放满了黑色或白色的棋子.对 (i, j) 位置进行一次操作后 (i, j), (i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1) 位置的棋子会变成原来相反的状态.问最少需要多少步可以将棋盘上的棋子全部变成白色或者黑色.

思路:分别将棋子变成黑色和白色,然后再用高斯消元解,其中步数较小者即为答案.

注意不存在唯一解时需要枚举自由变元来取得最小步数.

代码:

 #include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std; const int inf = 1e9;
const int MAXN = 3e2;
int equ, var;//有equ个方程,var个变元,增广矩正行数为equ,列数为var+1,从0开始计数
int a[MAXN][MAXN];//增广矩正
int free_x[MAXN];//用来存储自由变元(多解枚举自由变元可以使用)
int free_num;//自由变元个数
int x[MAXN];//解集 int Gauss(void){//返回-1表示无解,0表示有唯一解,否则返回自由变元个数
int max_r, col, k;
free_num = ;
for(k = , col = ; k < equ && col < var; k++, col++){
max_r = k;
for(int i = k + ; i < equ; i++){
if(abs(a[i][col] > abs(a[max_r][col]))) max_r = i;
}
if(a[max_r][col] == ){
k--;
free_x[free_num++] = col;//这个是变元
continue;
}
if(max_r != k){
for(int j = col; j < var + ; j++){
swap(a[k][j], a[max_r][j]);
}
}
for(int i = k + ; i < equ; i++){
if(a[i][col] != ){
for(int j = col; j < var + ; j++){
a[i][j] ^= a[k][j];
}
}
}
}
for(int i = k; i < equ; i++){
if(a[i][col] != ) return -;//无解
}
if(k < var) return var - k;//返回自由变元个数
for(int i = var - ; i >= ; i--){
x[i] = a[i][var];
for(int j = i + ; j < var; j++){
x[i] ^= (a[i][j] && x[j]);
}
}
return ;
} const int n = ;
string s[]; int solve(void){
int op = Gauss();
if(op == -) return inf;//无解
else if(op == ){//存在唯一解
int sol = ;
for(int i = ; i < var; i++){
sol += x[i];
}
return sol;
}else{//存在多解,需要枚举自由变元找到最小需要的操作数
int sol = inf;
int tot = << op;//有op个变元,每个变元可取0或1,共有1<<op总情况
for(int i = ; i < tot; i++){//二进制枚举,i二进制位上为1的取1,为0的取0
int cnt = ;
for(int j = ; j < op; j++){
if(i & ( << j)){//当前第j位变元取1
x[free_x[j]] = ;
cnt++;
}else x[free_x[j]] = ;
}
for(int j = var - op - ; j >= ; j--){
int idx;
for(idx = j; idx < var; idx++){
if(a[j][idx]) break;
}
x[idx] = a[j][var];
for(int l = idx + ; l < var; l++){
if(a[j][l]) x[idx] ^= x[l];
}
cnt += x[idx];
}
sol = min(sol, cnt);
}
return sol;
}
} void f(int op){
for(int i = ; i < n; i++){
for(int j = ; j < n; j++){
int cnt = i * n + j;
if(s[i][j] == 'w') a[cnt][var] = - op;
else a[cnt][var] = op;
x[cnt] = ;
}
}
for(int i = ; i < equ; i++){//构造增广矩阵
int x1 = i / n;
int y1 = i % n;
for(int j = ; j < var; j++){
int x2 = j / n;
int y2 = j % n;
if(abs(x1 - x2) + abs(y1 - y2) < ) a[j][i] = ;
else a[j][i] = ;
}
}
} void gel(void){
int sol = inf;
f();
sol = min(sol, solve());
f();
sol = min(sol, solve());
if(sol == inf) cout << "Impossible" << endl;
else cout << sol << endl;
} int main(void){
while(cin >> s[]){
equ = var = n * n;
for(int i = ; i < n; i++){
cin >> s[i];
}
gel();
}
return ;
}

poj1753(高斯消元解mod2方程组)的更多相关文章

  1. poj1830(高斯消元解mod2方程组)

    题目链接:http://poj.org/problem?id=1830 题意:中文题诶- 思路:高斯消元解 mod2 方程组 有 n 个变元,根据给出的条件列 n 个方程组,初始状态和终止状态不同的位 ...

  2. poj1222(枚举or高斯消元解mod2方程组)

    题目链接: http://poj.org/problem?id=1222 题意: 有一个 5 * 6 的初始矩阵, 1 表示一个亮灯泡, 0 表示一个不亮的灯泡. 对 (i, j) 位置进行一次操作则 ...

  3. poj1681(枚举or高斯消元解mod2方程组)

    题目链接: http://poj.org/problem?id=1681 题意: 有一个包含 n * n 个方格的正方形, w 表示其所在位置为白色, y 表示其所在位置为黄色. 对 (i, j) 位 ...

  4. 【高斯消元解xor方程组】BZOJ2466-[中山市选2009]树

    [题目大意] 给出一棵树,初始状态均为0,每反转一个节点的状态,相邻的节点(父亲或儿子)也会反转,问要使状态均为1,至少操作几次? [思路] 一场大暴雨即将来临,白昼恍如黑夜!happy! 和POJ1 ...

  5. POJ 1222 EXTENDED LIGHTS OUT(高斯消元解XOR方程组)

    http://poj.org/problem?id=1222 题意:现在有5*6的开关,1表示亮,0表示灭,按下一个开关后,它上下左右的灯泡会改变亮灭状态,要怎么按使得灯泡全部处于灭状态,输出方案,1 ...

  6. 【高斯消元解xor方程】BZOJ1923-[Sdoi2010]外星千足虫

    [题目大意] 有n个数或为奇数或为偶数,现在进行m次操作,每次取出部分求和,告诉你这几次操作选取的数和它们和的奇偶性.如果通过这m次操作能得到所有数的奇偶性,则输出进行到第n次时即可求出答案:否则输出 ...

  7. bzoj千题计划187:bzoj1770: [Usaco2009 Nov]lights 燈 (高斯消元解异或方程组+枚举自由元)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1770 a[i][j] 表示i对j有影响 高斯消元解异或方程组 然后dfs枚举自由元确定最优解 #in ...

  8. 【BZOJ】2466: [中山市选2009]树 高斯消元解异或方程组

    [题意]给定一棵树的灯,按一次x改变与x距离<=1的点的状态,求全0到全1的最少次数.n<=100. [算法]高斯消元解异或方程组 [题解]设f[i]=0/1表示是否按第i个点的按钮,根据 ...

  9. [置顶] hdu 4418 高斯消元解方程求期望

    题意:  一个人在一条线段来回走(遇到线段端点就转变方向),现在他从起点出发,并有一个初始方向, 每次都可以走1, 2, 3 ..... m步,都有对应着一个概率.问你他走到终点的概率 思路: 方向问 ...

随机推荐

  1. C Primer Plus学习笔记(四)- 运算符、表达式和语句

    基本运算符 赋值运算符:= 在C语言中,=不是“相等”,而是赋值运算符,把左边的值赋给右边的变量 a = 2018; //把值2018赋给变量a 赋值表达式语句的目的是把值储存到内存位置上,用于储存值 ...

  2. 部署和调优 1.1 nfs部署和优化-2

    更改共享目录文件默认的所有者和所属组 已知道客户端有个user11用户 cat /etc/passwd user11:x:501:501::/home/user11:/bin/bash 服务端打开 v ...

  3. JavaScript基础笔记集合(转)

    JavaScript基础笔记集合   JavaScript基础笔记集合   js简介 js是脚本语言.浏览器是逐行的读取代码,而传统编程会在执行前进行编译   js存放的位置 html脚本必须放在&l ...

  4. ruby 数组与散列

    def say_goodnight(name) result ="Good night ." +name return result end def say_goodmorning ...

  5. STM32数据类型定义

    #ifndef __STM32F10x_TYPE_H #define __STM32F10x_TYPE_H typedef signed long s32; typedef signed short ...

  6. g2o20160424 CMakeLists.txt

    LIB_PREFIX: 设置生成库的前缀 SET(LIB_PREFIX g2o_) # The library prefix SET(LIB_PREFIX g2o_) 变量的默认配置 # defaul ...

  7. Apache Thrift with Java Quickstart(thrift入门及Java实例)

    thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发.它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl ...

  8. 1.初学c++,比较困惑的问题。

    1.c++是一门实用的语言吗? c++是一个实用的工具,它很有用. 在工业软件世界中,c++被视为坚实和成熟的主流工具.它具有广泛的行业支持和好批. 2.面向对象编程在c++中的作用? 我们要开发一个 ...

  9. svg 标签

    SVG中的’defs’ and ‘use’-可复用的图元定义 在下一个示例中,我使用了defs中的元素之前,定义了如何去展现图元. <?xml version="1.0" s ...

  10. 树莓派研究笔记(10)-- Retropie 模拟器

    前面介绍过lakka模拟器,小巧,轻便,支持中文.其实最著名的游戏系统还是要属于Retropie啊.虽然笨重了一点,但是很多树莓派系统的原汁原味还是保留的很好.这样就不需要我们自己还要对lakka的源 ...