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

题意:格子有两面,1表示黑色格子,0表示白色格子,奶牛每次可以踩一个格子,踩到的格子和它周围的上下左右格子都会翻面,也即是颜色改变,
问:能不能踩有限个格子,使得所有格子都变成白色,如果能,求踩格子次数的方案,并且要求字典序(1)最小的那一个方案。
(1):字典序,可以百度一下哦。

思路:
纯暴力枚举:
M * N个格子,每个格子翻和不翻2种可能,时间复杂度O(2^M * N),显然不行。
改进的暴力方法:
我们想:一个格子的状态取决于本身的颜色加上本身翻与不翻和四周的四个格子翻与不翻,
再想,为了让上面的思考实现而且有条理,不如我们从第一行开始判断,直到最后一行,如果
全部是白色,说明该方法可以,否则不行。
那我们可以枚举第一行的所有翻与不翻的情况,假设一行有M个格子,那么第一行的情况有2^M,
,按照第一行的颜色情况,判断第二行每个格子翻与不翻使得第一行全部变成白色,。。。以此
类推,直到最后一行。
那时间复杂度差不多是O(M * N *2^M),M∈[1,15],可行。
那具体怎么做呢,
我们需要三个数组
mp[N][N]表示原来的格子情况
cur[N][N]表示当前每个格子翻与不翻的情况,1表示翻
ans[N][N]表示最后01矩阵的符合题目的答案
一个min_t记录最小翻转次数
一个tmp_t,某个方法的当前翻转次数

其实,一个棋子翻与不翻,我们就是为了改变它上面那一个格子的状态,那它上面那个格子的状态怎么确定呢,上面说了,那我们可以这么判断:上面那一个格子的颜色加上自身翻与不翻和上左右翻与不翻的情况,于是我们可以确定上面那一个格子的状态,于是我们就可以判断该格子也就是下面那个格子翻与不翻来把上面的格子变白色,每个格子都这么做,那么题目就变得简单了。


 #include <iostream>
#include <string.h>
#include <algorithm>
using namespace std; #define inf (1LL << 31) - 1
#define rep(i,j,k) for(int i = (j); i <= (k); i++)
#define rep_(i,j,k) for(int i = (j); i < (k); i++)
#define per(i,j,k) for(int i = (j); i >= (k); i--)
#define per_(i,j,k) for(int i = (j); i > (k); i--) const int N = ;
int mv_x[] = { , , , - };
int mv_y[] = { , -, , };
int ans[N][N];
int cur[N][N]; //记录的是翻与不翻的情况
int mp[N][N];
int min_t;
int tmp_t;
int n, m; inline void input(){
rep_(i, , n)rep_(j, , m){
cin >> mp[i][j];
}
} inline bool ok(int x,int y){
return (x >= && x < n && y >= && y < m);
} int search(int x, int y){
int k = mp[x][y]; //上面格子的颜色(1) rep(p, , ){ //上面格子自身和上左右的翻与不翻情况(2)
int dx = x + mv_x[p];
int dy = y + mv_y[p]; if (ok(dx, dy)){ //在地图界限内
k += cur[dx][dy];
}
} //如果(1) + (2) 为奇数说明上个格子为黑色返回1,否则是白色返回0
return k & ;
} void work(){ rep_(i, , n){
rep_(j, , m){
if (search(i - , j)){ //上个格子的情况
//上个格子是黑色
tmp_t++; //该格子翻转,使得上的格子变白色
cur[i][j] = ; //记录该格子的翻转情况
}
}
} //对最后一行检查,是否都是白色,不是直接结束该情况分支
rep_(j, , m){
if (search(n - , j)) return;
} //记录最优解
//我们枚举第一行的情况,且从000000000000000开始枚举
//那么每一个新的翻转次数一定是该反转次数字典序最小的
if (tmp_t < min_t){
min_t = tmp_t;
memcpy(ans, cur, sizeof(cur));
}
} //输出答案
inline void get_ans(){ if (min_t == inf){
cout << "IMPOSSIBLE" << endl;
return;
} rep_(i, , n){
cout << ans[i][];
rep_(j, , m) cout << " " << ans[i][j];
cout << endl;
}
} int main(){ ios::sync_with_stdio(false);
cin.tie(); cin >> n >> m; input(); //读取数据 min_t = inf;
// cout << min_t << endl;
rep_(i, , 1LL << m){ //第一行有 2^M种情况 tmp_t = ; //每种情况的次数初始化
memset(cur, , sizeof(cur)); //每种情况初始化 rep_(j, , m){
int t = (i >> j) & ; //二进制枚举第一行翻与不翻情况
//比如一行有15个格子就是2^15种情况
//000000000000000
//可以表示0~2^15 - 1,就是2^15种情况
//每一位0或者1表示翻与不翻 cur[][m - - j] = t; //每一位对1来与(&),然后记录 if (t) tmp_t++; //如果t是1,那就是第一行某个格子翻
} work();
}
get_ans(); return ;
}

kuangbin专题 专题一 简单搜索 Fliptile POJ - 3279的更多相关文章

  1. kuangbin专题 专题一 简单搜索 Pots POJ - 3414

    题目链接:https://vjudge.net/problem/POJ-3414 题意:给你两个杯子,分别容量为A(1),B(2)和一个C,C是需要经过下列操作,得到的一个升数.(1) FILL(i) ...

  2. kuangbin专题总结一 简单搜索

    A - 棋盘问题:在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有 ...

  3. Enum:Fliptile(POJ 3279)

    Fliptile 题目大意:农夫想要测牛的智商,于是他把牛带到一个黑白格子的地,专门来踩格子看他们能不能把格子踩称全白 这一题其实就是一个枚举题,只是我们只用枚举第一行就可以了,因为这一题有点像开关一 ...

  4. Fliptile POJ - 3279 (开关问题)

    Fliptile Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16483   Accepted: 6017 Descrip ...

  5. Fliptile(POJ 3279)

    原题如下: Fliptile Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16494   Accepted: 6025 D ...

  6. [kuangbin带你飞]专题一 简单搜索(回顾)

    A - 棋盘问题 POJ - 1321 注意条件:不能每放一个棋子,就标记一行和一列,我们直接枚举每一行就可以了. AC代码: #include<iostream> #include< ...

  7. 简单搜索 kuangbin C D

    C - Catch That Cow POJ - 3278 我心态崩了,现在来回顾很早之前写的简单搜索,好难啊,我怎么写不出来. 我开始把这个写成了dfs,还写搓了... 慢慢来吧. 这个题目很明显是 ...

  8. 搜索入门_简单搜索bfs dfs大杂烩

    dfs题大杂烩 棋盘问题  POJ - 1321 和经典的八皇后问题一样.  给你一个棋盘,只有#区域可以放棋子,同时同一行和同一列只能有一个棋子. 问你放k个棋子有多少种方案. 很明显,这是搜索题. ...

  9. [kuangbin带你飞]专题一 简单搜索

            ID Origin Title 454 / 1008 Problem A POJ 1321 棋盘问题   328 / 854 Problem B POJ 2251 Dungeon Ma ...

随机推荐

  1. Socket 专题

    Socket小白篇-附加TCP/UDP简介 Socket 网络通信的要素 TCP和UDP Socket的通信流程图 1.Socket 什么是Socket Socket:又称作是套接字,网络上的两个程序 ...

  2. Android SharedPreferences中apply和commit的效率差距

    Android SharedPreferences中apply和commit的效率差距 经常看到它俩的速度有差别,apply和commit.到底差距多少,下面做一个统计.   apply commit ...

  3. C#基础加强篇----委托、Lamada表达式和事件(上)

    1.委托 C#的委托相当于C/C++中的函数指针.函数指针用指针获取一个函数的入口地址,实现对函数的操作. 委托与C/C++中的函数指针不同在于,委托是面向对象的,是引用类型,对委托的使用要先定义后实 ...

  4. murmurhash2算法 和 DJB Hash算法是目前最流行的hash算法

    murmurhash2算法 和 DJB Hash算法是目前最流行的hash算法 1.DJB HASH算法 1 2 3 4 5 6 7 8 9 10 11 /* the famous DJB Hash ...

  5. C# Oracle数据库操作类

    using System; using System.Data; using System.Collections.Generic; using System.Configuration; using ...

  6. 基于VUE实现的新闻后台管理系统-二

    基础环境及最后的开发效果已完成说明,接下来就开始配置. ¶npm初始化 新建项目文件夹VueDemo,在其内执行如下脚本 npm init -y 安装vue-cli构建包 yarn add vue-c ...

  7. 【备忘】C#语言基础-1

    C#基础 注意区别哟! C#是一种托管语言,与C++不同,不能直接操作系统底层,依赖于 framework. 如果局部变量和全局变量同名,全局变量就会被屏蔽. 函数的返回值类型不是签名的一部分,所以不 ...

  8. C#整数类型

    C#支持9种整数类型,sbyte,byte,short,ushort,int,uint,long,ulong和char. 类型 含义                                  ...

  9. QT 强制杀死进程

    bool KillProcess(QString ProcessName){  bool result = false; QString str1; HANDLE hSnapShot = Create ...

  10. Realm_King 之 XPDL(XML Process Definition Language)

    XPDL(XML Process Definition Language)是由Workflow Management Coalition(简写为:WfMC)所提出的一个标准化规格,使用XML文件让不同 ...