POJ:3279-Fliptile【状态压缩】【DFS】
经典【状态压缩】【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】的更多相关文章
- POJ 3279 Fliptile 状态压缩,思路 难度:2
http://poj.org/problem?id=3279 明显,每一位上只需要是0或者1, 遍历第一行的所有取值可能,(1<<15,时间足够)对每种取值可能: 对于第0-n-2行,因为 ...
- 状态压缩+枚举 POJ 3279 Fliptile
题目传送门 /* 题意:问最少翻转几次使得棋子都变白,输出翻转的位置 状态压缩+枚举:和之前UVA_11464差不多,枚举第一行,可以从上一行的状态知道当前是否必须翻转 */ #include < ...
- POJ 3279 Fliptile(翻格子)
POJ 3279 Fliptile(翻格子) Time Limit: 2000MS Memory Limit: 65536K Description - 题目描述 Farmer John kno ...
- poj 3311(状态压缩DP)
poj 3311(状态压缩DP) 题意:一个人送披萨从原点出发,每次不超过10个地方,每个地方可以重复走,给出这些地方之间的时间,求送完披萨回到原点的最小时间. 解析:类似TSP问题,但是每个点可以 ...
- poj 1185(状态压缩DP)
poj 1185(状态压缩DP) 题意:在一个N*M的矩阵中,‘H'表示不能放大炮,’P'表示可以放大炮,大炮能攻击到沿横向左右各两格,沿纵向上下各两格,现在要放尽可能多的大炮使得,大炮之间不能相互 ...
- poj 3254(状态压缩DP)
poj 3254(状态压缩DP) 题意:一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相 ...
- POJ.3279 Fliptile (搜索+二进制枚举+开关问题)
POJ.3279 Fliptile (搜索+二进制枚举+开关问题) 题意分析 题意大概就是给出一个map,由01组成,每次可以选取按其中某一个位置,按此位置之后,此位置及其直接相连(上下左右)的位置( ...
- 【POJ 3279 Fliptile】开关问题,模拟
题目链接:http://poj.org/problem?id=3279 题意:给定一个n*m的坐标方格,每个位置为黑色或白色.现有如下翻转规则:每翻转一个位置的颜色,与其四连通的位置都会被翻转,但注意 ...
- POJ 3279(Fliptile)题解
以防万一,题目原文和链接均附在文末.那么先是题目分析: [一句话题意] 给定长宽的黑白棋棋盘摆满棋子,每次操作可以反转一个位置和其上下左右共五个位置的棋子的颜色,求要使用最少翻转次数将所有棋子反转为黑 ...
- POJ - 3279 Fliptile (枚举)
http://poj.org/problem?id=3279 题意 一个m*n的01矩阵,每次翻转(x,y),那么它上下左右以及本身就会0变1,1变0,问把矩阵变成全0的,最小需要点击多少步,并输出最 ...
随机推荐
- 每日总结9.20-phoenix的连接
今天连了phoenix 出现了好多问题,欸 一点点解决,看那个电脑我头都要晕了,jar包和xml文件的问题,总之是解决了 怎么办,我还不会springboot,好多人都学了,我害怕.大家怎么都这么努力 ...
- 如何使用 PreparedStatement 来避免 SQL 注入,并提高性能?
前言 本篇文章主要如何使用 PreparedStatement 来避免 SQL 注入,并提高性能? 欢迎点赞 收藏 留言评论 私信必回哟 博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言 ...
- 什么是RPC协议
工作的时候,第一次接触CRPC协议,当时就很懵,啥是CRPC协议,一脸懵逼,于是就到网上去搜,填充知识空缺. 不少解释显得非常官方,我相信大家在各种平台上也都看到过,解释了又好像没解释,都在用一个我们 ...
- Spring Cache + Caffeine的整合与使用
前言 对于一些项目里需要对数据库里的某些数据一直重复请求的,且这些数据基本是固定的,在这种情况下,可以借助简单使用本地缓存来缓存这些数据.这些介绍一下Spring Cache和Caffeine的使用. ...
- 衡兰芷若成绝响,人间不见周海媚(4k修复基于PaddleGan)
一代人有一代人的经典回忆,1994年由周海媚.马景涛.叶童主演的<神雕侠侣>曾经风靡一时,周海媚所诠释的周芷若凝聚了汉水之钟灵,峨嵋之毓秀,遇雪尤清,经霜更艳,俘获万千观众,成为了一代人的 ...
- [CSP-S 2023] 密码锁
题目描述 小 Y 有一把五个拨圈的密码锁.如图所示,每个拨圈上是从 \(0\) 到 \(9\) 的数字.每个拨圈都是从 \(0\) 到 \(9\) 的循环,即 \(9\) 拨动一个位置后可以变成 \( ...
- Keepalived 高可用详解
Keepalived 详解 1.Keepalived介绍 Keepalived是一个基于VRRP协议来实现LVS服务高可用方案,可以利用其来避免单点故障.一个LVS服务会使用2台服务器运行Keep ...
- 什么是革命性技术eBPF?为什么可观测性领域都得用它
公众号「架构成长指南」,专注于生产实践.云原生.分布式系统.大数据技术分享. 如果有一种技术可以监控和采集任何应用信息,支持任何语言,并且应用完全无感知,零侵入,想想是不是很激动,那么这个技术是什么呢 ...
- Mysql索引失效的几种原因-mysql-suo-yin-shi-xiao-de-ji-zhong-yuan-yin
title: Mysql索引失效的几种原因 date: 2021-07-15 17:13:59.019 updated: 2021-12-26 17:43:12.489 url: https://ww ...
- Redis 打怪升级进阶成神之路(2023 最新版)!
前面我们学习:MySQL 打怪升级进阶成神之路(2023 最新版)!,然后我们就开始了 NoSQL 卷王之路.从第一篇文章开始,我们逐步详细介绍了 Redis 基础理论与安装配置.9 种数据类型和应用 ...