POJ-3279


经典【状态压缩】【DFS】题型

题目大意:有一个 M * N 的格子,每个格子可以翻转正反面,它们有一面是黑色,另一面是白色。黑色翻转之后变成白色,白色翻转之后则变成黑色。
游戏要做的是把所有的格子翻转为白色。不过因为牛蹄很大,所以每次翻转一个格子,与它上下左右相邻接的格子也会被翻转。
求用最小的步数完成时,每个格子的翻转次数。最小步数的解有多个时,输出字典序最小的一组;解不存在的话,则输出IMPOSSIBLE 题目样例:0表示白色,1表示黑色 1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1 题目思路:首先,同一个格子翻转两次就会恢复原状,所以多次翻转是多余的。此外,翻转的格子的集合相同的话,其次序是无关紧要的。 不妨先指定好最上面一行的翻转方法。此时,能翻转(1,1)的只剩下了(2,1),所以可以直接判断(2,1)是否需要翻转。类似的(2,1)~(2,N)都能这样判断,
如此反复下去就能确定所有格子的翻转方法,最后(M,1)~(M,N)并非全为白色,则意味着不存在可行的操作方法。 像这样,先确定第一行的翻转方式,然后可以很容易判断这样是否存在解以及解的最小步数是多少,这样将第一行的所有翻转方式都尝试一次就能求出整个问题的最小步数。这个算法中最上面
一行的翻转方式共有2^N种,复杂度为O(M * N * 2^N)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>
#include<iomanip>
using namespace std;
const int maxn = 16;
int M, N;
const int dx[5] = { -1,0,0,0,1 };
const int dy[5] = { 0,-1,0,1,0 };
int tile[maxn][maxn];
int opt[maxn][maxn]; //保存最优解
int flip[maxn][maxn]; //保存中间结果 //查询(x,y)的颜色
int get(int x, int y)
{
int c = tile[x][y]; //注意这里要加上原来的状态
for (int d = 0; d < 5; d++) //查询周围四个以及自己的翻转次数
{
int x2 = x + dx[d], y2 = y + dy[d];
if (0 <= x2 && x2 < M && 0 <= y2 && y2 < N)
{
c += flip[x2][y2];
}
}
return c % 2; //奇数为1,偶数为0
} //求出第1行确定的情况下的最小操作次数
//不存在解得话,返回-1
int calc()
{
//求出从第2行开始的翻转方法
for (int i = 1; i < M; i++)
{
for (int j = 0; j < N; j++)
{
if (get(i - 1, j) != 0)
{
//如果(i- 1,j)是黑色的话,则必须翻转这个格子
flip[i][j] = 1;
}
}
}
//判断最后一行是否全白
for (int j = 0; j < N; j++)
{
//无解
if (get(M - 1, j) != 0) return -1;
} //统计翻转次数
int res = 0;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
res += flip[i][j];
}
}
return res;
}
void solve()
{
int res = -1;
//按照字典序尝试第一行的所有可能性
for (int i = 0; i < 1 << N; i++) //i表示一个二进制数,用来枚举第1行的各种不同翻法,如0001就是只翻最后一个
{
memset(flip, 0, sizeof(flip));
for (int j = 0; j < N; j++)
{
flip[0][N - j - 1] = i >> j & 1;
/*eg:0011001
①j == 0; i >> j 即0011001 & 1 -> 1
②j == 1; i >> j 即0001100 & 1 -> 0
...
每次取出最后一位,存入flip中
*/
}
int num = calc(); //num记录翻转次数
if (num >= 0 && (res < 0 || res > num)) //如果找到一种可能并且所用步数更少的话,记下这种翻法
{
res = num;
memcpy(opt, flip, sizeof(flip));
}
}
if (res < 0)
//无解
printf("IMPOSSIBLE\n");
else //最后找到的就是最少的翻法,模拟一遍,然后输出
for (int i = 0; i < M; i++)
for (int j = 0; j < N; j++)
printf("%d%c", opt[i][j], j + 1 == N ? '\n' : ' ');
}
int main()
{
cin >> M >> N;
for (int i = 0; i < M; i++) //数据输入
for (int j = 0; j < N; j++)
cin >> tile[i][j]; //0表示白色,1表示黑色
solve();
return 0;
}

POJ:3279-Fliptile【状态压缩】【DFS】的更多相关文章

  1. POJ 3279 Fliptile 状态压缩,思路 难度:2

    http://poj.org/problem?id=3279 明显,每一位上只需要是0或者1, 遍历第一行的所有取值可能,(1<<15,时间足够)对每种取值可能: 对于第0-n-2行,因为 ...

  2. 状态压缩+枚举 POJ 3279 Fliptile

    题目传送门 /* 题意:问最少翻转几次使得棋子都变白,输出翻转的位置 状态压缩+枚举:和之前UVA_11464差不多,枚举第一行,可以从上一行的状态知道当前是否必须翻转 */ #include < ...

  3. POJ 3279 Fliptile(翻格子)

    POJ 3279 Fliptile(翻格子) Time Limit: 2000MS    Memory Limit: 65536K Description - 题目描述 Farmer John kno ...

  4. poj 3311(状态压缩DP)

    poj  3311(状态压缩DP) 题意:一个人送披萨从原点出发,每次不超过10个地方,每个地方可以重复走,给出这些地方之间的时间,求送完披萨回到原点的最小时间. 解析:类似TSP问题,但是每个点可以 ...

  5. poj 1185(状态压缩DP)

    poj  1185(状态压缩DP) 题意:在一个N*M的矩阵中,‘H'表示不能放大炮,’P'表示可以放大炮,大炮能攻击到沿横向左右各两格,沿纵向上下各两格,现在要放尽可能多的大炮使得,大炮之间不能相互 ...

  6. poj 3254(状态压缩DP)

    poj  3254(状态压缩DP) 题意:一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相 ...

  7. POJ.3279 Fliptile (搜索+二进制枚举+开关问题)

    POJ.3279 Fliptile (搜索+二进制枚举+开关问题) 题意分析 题意大概就是给出一个map,由01组成,每次可以选取按其中某一个位置,按此位置之后,此位置及其直接相连(上下左右)的位置( ...

  8. 【POJ 3279 Fliptile】开关问题,模拟

    题目链接:http://poj.org/problem?id=3279 题意:给定一个n*m的坐标方格,每个位置为黑色或白色.现有如下翻转规则:每翻转一个位置的颜色,与其四连通的位置都会被翻转,但注意 ...

  9. POJ 3279(Fliptile)题解

    以防万一,题目原文和链接均附在文末.那么先是题目分析: [一句话题意] 给定长宽的黑白棋棋盘摆满棋子,每次操作可以反转一个位置和其上下左右共五个位置的棋子的颜色,求要使用最少翻转次数将所有棋子反转为黑 ...

  10. POJ - 3279 Fliptile (枚举)

    http://poj.org/problem?id=3279 题意 一个m*n的01矩阵,每次翻转(x,y),那么它上下左右以及本身就会0变1,1变0,问把矩阵变成全0的,最小需要点击多少步,并输出最 ...

随机推荐

  1. 小程序的登录授权与退出功能(wx.getUserProfile)

    一.授权登录:wx.getUserProfile 1.使用wx.getUserProfile实现登录 1.javascript: login(){ wx.getUserProfile({ desc: ...

  2. Macbook磁盘系统结构/文件/目录介绍分析

    1. 系统磁盘根目录详解: 1.1 磁盘根目录结构 / (根目录)|-- Applications # 存放应用程序|-- Users # 存放用户文件和设置|-- cores # 存放核心转储文件, ...

  3. Go语言实现GoF设计模式:适配器模式

    本文分享自华为云社区<[Go实现]实践GoF的23种设计模式:适配器模式>,作者:元闰子. 简介 适配器模式(Adapter)是最常用的结构型模式之一,在现实生活中,适配器模式也是处处可见 ...

  4. [VBA] 实现SQLserver数据库的增删改查

    [VBA] 实现 SQLserver数据库的增删改查 问题背景 用于库存管理的简单Excel系统实现,能够让库管员录入每日出入库信息并进能够按日期查询导出数据,生成简要报表,以及数据修改与删除.非科班 ...

  5. Hexo 主题开发之自定义模板

    关于 Hexo 如何开发主题包的教程在已经是大把的存在了,这里就不在赘述了.这边文章主要讲的是作为一个主题的开发者,如何让你的主题具有更好的扩展性,在用户自定义修改主题后,能够更加平易升级主题. 问题 ...

  6. 阿里云AnalyticDB基于Flink CDC+Hudi实现多表全增量入湖实践

    湖仓一体(LakeHouse)是大数据领域的重要发展方向,提供了流批一体和湖仓结合的新场景.阿里云AnalyticDB for MySQL基于 Apache Hudi 构建了新一代的湖仓平台,提供日志 ...

  7. 推荐给前端开发的 5 款 Chrome 扩展 🚀

    大家好,我是 dom 哥.这是我关于 Chrome 扩展开发的系列文章,感兴趣的可以 点个小星星. 工欲善其事,必先利其器.Chrome 可能是前端开发中使用最多的浏览器.在日常开发中,下列几款 Ch ...

  8. SpringBoot 这么实现动态数据源切换,就很丝滑!

    大家好,我是小富- 简介 项目开发中经常会遇到多数据源同时使用的场景,比如冷热数据的查询等情况,我们可以使用类似现成的工具包来解决问题,但在多数据源的使用中通常伴随着定制化的业务,所以一般的公司还是会 ...

  9. 推荐一款功能齐全的开源MES/万界星空科技mes

    推荐一款功能齐全的开源MES 万界星空科技商业开源MES可以提供包括制造数据管理.计划排程管理.生产调度管理.库存管理.质量管理.人力资源管理.工作中心/设备管理.工具工装管理.采购管理.成本管理.项 ...

  10. 【UniApp】-uni-app-打包成小程序

    前言 大家好,我是 BNTang, 在上一节文章中,我给大家详细的介绍了如何将我开发好的项目打包为网页. 趁热打铁,在来一篇文章,给大家详细的介绍如何将项目打包为小程序. 正文 打开微信小程序呢,其实 ...