POJ 3279 Fliptile(DFS+反转)

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

题目大意:有一个n*m的格子,每个格子都有黑白两面(0表示白色,1表示黑色)。我们需要把所有的格子都反转成黑色,每反转一个格子,它上下左右的格子都会跟着反转。请求出用最小步数完成反转时每个格子反转的次数。有多个解时,输出字典序最小的一组。

解题思路:只要枚举第一行的2^m种情况,如果一个位置上一行是1,那这个位置一定要反转,因为只有这一行能改变上一行,所以每一行的状态都是由前一行决定的。只要最后判断最后一行是不是都是0即可,关于最小字典序,只要从右往左枚举,第一个方案就是正解。(时间复杂度O(n*m*2^m)。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int N=20;
 5
 6 int n,m;
 7 bool flag;
 8 int map[N][N],sta[N][N],tmp[N][N];//sta表示踩或不踩
 9 int d[5][2]={{0,1},{1,0},{0,0},{0,-1},{-1,0}};
10
11
12 //反转坐标为(i,j)的格子
13 void reverse(int i,int j,int s[][N]){
14     for(int k=0;k<5;k++){
15         int x=i+d[k][0];
16         int y=j+d[k][1];
17         s[x][y]=!s[x][y];
18     }
19 }
20
21 void dfs(int y){
22     if(flag)
23         return;
24     if(y>=1){
25         //不踩
26         sta[1][y]=0;
27         dfs(y-1);
28         //踩
29         sta[1][y]=1;
30         reverse(1,y,map);
31         dfs(y-1);
32         reverse(1,y,map);
33     }
34     else{
35         for(int i=1;i<=n;i++){
36             for(int j=1;j<=m;j++){
37                 tmp[i][j]=map[i][j];
38             }
39         }
40         for(int i=2;i<=n;i++){
41             for(int j=1;j<=m;j++){
42                 sta[i][j]=0;
43                 if(tmp[i-1][j]==1){
44                     reverse(i,j,tmp);
45                     sta[i][j]=1;
46                 }
47             }
48         }
49
50         bool sign=true;
51         for(int i=1;i<=m;i++){
52             if(tmp[n][i]==1){
53                 sign=false;
54                 break;
55             }
56         }
57         if(sign){
58             flag=true;
59             for(int i=1;i<=n;i++){
60                 for(int j=1;j<=m;j++){
61                     if(j==m)
62                         printf("%d\n",sta[i][j]);
63                     else
64                         printf("%d ",sta[i][j]);
65                 }
66             }
67         }
68     }
69 }
70
71 int main(){
72     while(~scanf("%d%d",&n,&m)){
73         memset(sta,0,sizeof(sta));
74         flag=false;
75         for(int i=1;i<=n;i++){
76             for(int j=1;j<=m;j++){
77                 scanf("%d",&map[i][j]);
78             }
79         }
80         dfs(m);
81         if(!flag)
82             puts("IMPOSSIBLE");
83     }
84     return 0;
85 }
时间: 2024-10-21 21:40:24

POJ 3279 Fliptile(DFS+反转)的相关文章

状态压缩+枚举 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

POJ 3279(Fliptile)题解

以防万一,题目原文和链接均附在文末.那么先是题目分析: [一句话题意] 给定长宽的黑白棋棋盘摆满棋子,每次操作可以反转一个位置和其上下左右共五个位置的棋子的颜色,求要使用最少翻转次数将所有棋子反转为黑色所需翻转的是哪些棋子(这句话好长...). [题目分析] 盯着奇怪的题目看了半天发现和奶牛没什么卵关系..奶牛智商高了产奶高是什么鬼说法... 这题刚开始被放到搜索的分类下了..然而这和搜索有什么关系..没经验所以想了各种和搜索沾边的方法,结果没想出解法,直到看了网上的题解,压根不是搜索啊有木有.

poj 3279 Fliptile (简单搜索)

Fliptile Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16558   Accepted: 6056 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 whic

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

poj 3279 Fliptile

Fliptile Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4864   Accepted: 1862 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 状态压缩,思路 难度:2

http://poj.org/problem?id=3279 明显,每一位上只需要是0或者1, 遍历第一行的所有取值可能,(1<<15,时间足够)对每种取值可能: 对于第0-n-2行,因为上一行和本身行都已确定,所以可以确定下一行 最后检查第n-1行是否满足条件即可 #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace

POJ 3279 Fliptile(翻转)

题目链接:http://poj.org/problem?id=3279 题意:n*m棋盘区域,由0和1填充,0白,1,黑,(正反两面颜色各异)通过翻转操作使棋盘全部白色朝上,每次翻转棋子,棋子周围(上下左右)都要被翻转,问是否可能翻转 翻转成功,如果翻转成功,输出最少的翻转次数下每个棋子的翻转次数. 题解:有m列,所以最多有2^m种可能性,枚举第一行.然后从第i行(i从2开始)先开始考虑第i-1行,然后依次往下推,再判断最后一行是不是都翻转成白色. 1 #include <string> 2