POJ-3279.Fliptile(二进制状态压缩 + dfs) 子集生成

  昨天晚上12点刷到的这个题,一开始一位是BFS,但是一直没有思路。后来推了一下发现只需要依次枚举第一行的所有翻转状态然后再对每个情况的其它田地翻转进行暴力dfs就可以,但是由于二进制压缩学的不是很透,一直有小问题,下面我还会讲子集生成的相关方法,有兴趣的同学可以继续关注。

  本题大意:一块地,有黑(1)白(0)之分,牛每次踩踏使得当前块以及四连块都变色,问当牛如何踩时使得地都变白并且求出最小踩踏次数和踩踏路径的最小字典序时的踩踏地图。

  本题思路:由于同一块地被翻两次都会回到原来的状态,所以只需要对应每块地看他上方的地是否为黑色,为黑色则翻否则看其他情况,由于第一排的黑色只有第二排能翻,所以需要先对第一排进行枚举,然后再对其剩余的状态进行搜索即可。那么如何判断某块地是否为黑色呢,这里我们采用二进制压缩,大意就是从1 -(1 << n) 的所有数字即逆序枚举了所有状态,然后访问每个状态,如果此地上方的为白色地则跳过,黑色地则进行翻转。具体如下图所示。

  首先我们假设有m == 4列,则它所对应的数字如下图所示。

每个数对应的二进制码位如果为1则翻转,否则不翻转。

  参考代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4
 5 const int maxn = 15 + 5, INF = 0x3f3f3f;
 6 int n, m, minx = INF;
 7 int maze[maxn][maxn], temp[maxn][maxn], vis[maxn][maxn], ans[maxn][maxn];
 8 int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
 9
10 void reverse(int u, int v) {
11     vis[u][v] = 1;
12     temp[u][v] = !temp[u][v];
13     for(int p = 0; p < 4; p ++) {
14             int ni = u + dx[p], nj = v + dy[p];
15             if(ni >= 0 && nj >= 0 && ni < n && nj < m)
16                 temp[ni][nj] = !temp[ni][nj];
17     }
18 }
19
20 bool Judge() {
21     for(int i = 0; i < n; i ++)
22         for(int j = 0; j < m; j ++)
23             if(temp[i][j] == 1)    return false;
24     return true;
25 }
26
27 void solve(int x) {
28     memcpy(temp, maze, sizeof(maze));
29     memset(vis, 0, sizeof(vis));
30     int cnt = 0;
31     for(int i = 0; i < m; i ++) {
32         if((x >> i) & 1) {
33             cnt ++;
34             reverse(0, i);
35         }
36     }
37     for(int i = 1; i < n; i ++) {
38         for(int j = 0; j < m; j ++) {
39             if(temp[i - 1][j] == 1) {
40                 reverse(i, j);
41                 cnt ++;
42             }
43         }
44     }
45     if(Judge() && cnt < minx) {
46         minx = cnt;
47         memcpy(ans, vis, sizeof(vis));
48     }
49 }
50
51 int main () {
52     scanf("%d %d", &n, &m);
53     for(int i = 0; i < n; i ++)
54         for(int j = 0; j < m; j++)
55             scanf("%d", &maze[i][j]);
56     for(int i = 0; i < (1 << m); i ++)
57         solve(i);
58     if(minx == INF)
59         printf("IMPOSSIBLE\n");
60     else {
61         for(int i = 0; i < n; i ++) {
62             for(int j = 0; j < m - 1; j ++) {
63                 printf("%d ", ans[i][j]);
64             }
65             printf("%d\n", ans[i][m - 1]);
66         }
67     }
68     return 0;
69 }

View Cod

原文地址:https://www.cnblogs.com/bianjunting/p/10489116.html

时间: 2024-11-03 10:18:42

POJ-3279.Fliptile(二进制状态压缩 + dfs) 子集生成的相关文章

POJ 3279 Fliptile (二进制枚举+模拟)

Fliptile Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3992   Accepted: 1518 Description Farmer John knows that an intellectually satisfied cow is a happy cow who will give more milk. He has arranged a brainy activity for cows in which

poj 3279 Fliptile(二进制)

http://poj.org/problem?id=3279 在n*N的矩阵上,0代表白色,1代表黑色,每次选取一个点可以其颜色换过来,即白色变成黑色,黑色变成白色,而且其上下左右的点颜色也要交换,求最少交换多少点能把全部换成颜色0 输出所需要换的点,用1表示,如果有多种方案,输出字典序足最小的方案 但是这题的数据里没有字典序的情况,所以没有比较字典序也可以过,我一开始就不知道这个怎么按字典序排 用二进制枚举第一行所有的情况,第一行的情况确定了,下面的就确定了 1 #include<cstdio

poj 3279 Fliptile(二进制暴力)

Fliptile Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3629   Accepted: 1400 Description Farmer John knows that an intellectually satisfied cow is a happy cow who will give more milk. He has arranged a brainy activity for cows in which

状态压缩+枚举 POJ 3279 Fliptile

题目传送门 1 /* 2 题意:问最少翻转几次使得棋子都变白,输出翻转的位置 3 状态压缩+枚举:和之前UVA_11464差不多,枚举第一行,可以从上一行的状态知道当前是否必须翻转 4 */ 5 #include <cstdio> 6 #include <cstring> 7 #include <algorithm> 8 using namespace std; 9 10 const int MAXN = 20; 11 const int INF = 0x3f3f3f3

POJ2411——状态压缩+DFS——Mondriaan&#39;s Dream

Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series' (where he had to use his toilet paper to draw on, for all of his paper was filled with squares and r

POJ 3254 Corn Fields 状态压缩DP (C++/Java)

http://poj.org/problem?id=3254 题目大意: 一个农民有n行m列的地方,每个格子用1代表可以种草地,而0不可以.放牛只能在有草地的,但是相邻的草地不能同时放牛, 问总共有多少种方法. 思路: 状态压缩的DP. 可以用二进制数字来表示放牧情况并判断该状态是否满足条件. 这题的限制条件有两个: 1.草地限制. 2.相邻限制. 对于草地限制,因为输入的时候1是可以种草地的. 以"11110"草地分析,就只有最后一个是不可以种草的.取反后得00001  .(为啥取反

# 最短Hamilton路径(二进制状态压缩)

最短Hamilton路径(二进制状态压缩) 题目描述:n个点的带权无向图,从0-n-1,求从起点0到终点n-1的最短Hamilton路径(Hamilton路径:从0-n-1不重不漏的每个点恰好进过一次) 题解:二进制状态压缩算法\(O(2^n*n^2)\),需要记录当前经过了哪些点,当前在哪个位置.\(f[i][j]\) ? \(i\)转化为二进制每一位代表是否经过该点,\(j\)表示当前位于j这个点 #include <iostream> #include <cstring> u

二进制状态压缩及位运算

位运算符: 与(&),或(|),非(~), 异或(^); 移位运算: 1.左移:在二进制表示下把数字同时向左移动,低位以0填充,高位越界后舍弃 1 << n = 2^n, n << 1 = 2n 2.算术右移:在二进制补码表示下把数字同时向右移动,高位以符号位填充,低位越界后舍弃 n >> 1 = n/2.0(向下取整) eg:(-3)>> 1 = -2, 3 >> 1 = 1;  二进制状态压缩,是指将一个n位的 bool 数组用 n

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

题目链接:http://poj.org/problem?id=3279 题意:给定一个n*m的坐标方格,每个位置为黑色或白色.现有如下翻转规则:每翻转一个位置的颜色,与其四连通的位置都会被翻转,但注意只扩散一圈,不是连锁反应. 求最少翻转几个位置能够使所有n*m个位置都变为白色.若有解,求字典序最小的翻转方案(给出每个位置的翻转次数). 数据范围:n, m 属于 [1, 15] 思路:我们把翻转方案中的翻转称为“主动翻转”,翻转过程中受邻居影响而发生的翻转称为“被动翻转”.观察例子可得出如下几个