poj 3279(暴力)

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

思路就是先判断第一行,然后如果第一行确定了,那么第二行就必须确定了(如果第一行某个是黑色的,那么必定要在第二行给它翻过来),所以一直到底m-1行都是确定的,接下来只要判断第m行是否是全白就好了。直接枚举第一行就可以,代码是我参考大神的代码写的,里面的二进制枚举操作还是看了有一会儿才看懂

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;

const int N = 20;
int gh[N][N];//初试的数组
int ch[N][N];//操作的数组
int vis[N][N];//记录翻过的牌子
int re[N][N];//
int ans[N][N];//记录答案

int fNum,aNum,n,m;

void solve( int i,int j ){
    fNum++;//操作次数+1
    vis[i][j] = 1;
    ch[i][j] = 1 - ch[i][j];
    ch[i-1][j] = 1 - ch[i-1][j];
    ch[i][j-1] = 1 - ch[i][j-1];
    ch[i+1][j] = 1 - ch[i+1][j];
    ch[i][j+1] = 1 - ch[i][j+1];
}

void record(){
    aNum = fNum;//最小次数记录一下
    for( int i = 1; i <= m; i++ ){
        for( int j = 1; j <= n; j++ ){
            ans[i][j] = vis[i][j];
        }
    }
}

int main(){
    cin >> m >> n;
    for( int i = 1; i <= m; i++ ){
        for( int j = 1; j <= n; j++ ){
            cin >> gh[i][j];
        }
    }
    aNum = 10010;
    int t = 1 << n;
    for( int loop = 0; loop < t; loop++ ){
        for( int i = 1; i <= m; i++ ){
            for( int j = 1; j <= n; j++ ){
                ch[i][j] = gh[i][j];
            }
        }
        memset(vis,0,sizeof(vis));
        fNum = 0;//记录需要操作的数目
        int moveN = loop;//这里是二进制,二进制
        for( int i = 1; i <= n; i++ ){
            if( moveN&1 ){//这里我看了很久才看明白
                //假入一个数字的二进制是0101,意思就是
                //第一格翻,第三格翻,上面t为2的N次方,包括了所有的
                //可能性的二进制对应的数字
                solve( 1,i );
            }
            moveN >>= 1;
        }
        for( int i = 2; i <= m; i++ ){
            for( int j = 1; j <= n; j++ ){
                if( ch[i-1][j] ){//如果上一行是黑色,就处理这一行
                    solve(i,j);
                }
            }
        }
        bool flag = true;
        for( int j = 1; j <= m; j++ ){
            if( ch[m][j] ){//直接判断最后一行是否满足
                flag = false;
                break;
            }
        }
        if( flag and fNum < aNum ){
            record();
        }
    }
    if( aNum == 10010 ){
        cout << "IMPOSSIBLE\n";
        return 0;
    }else{
        for( int i = 1; i <= m; i++ ){
            cout << ans[i][1];
            for( int j = 2; j <= n; j++ ){
                cout << " " << ans[i][j];
            }
            cout << endl;
        }
    }
}
时间: 2024-08-01 23:35:46

poj 3279(暴力)的相关文章

POJ 2329 (暴力+搜索bfs)

Nearest number - 2 Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 3943 Accepted: 1210 Description Input is the matrix A of N by N non-negative integers. A distance between two elements Aij and Apq is defined as |i ? p| + |j ? q|. Your pro

状态压缩+枚举 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: 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】开关问题,模拟

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

POJ 3279 Fliptile(DFS+反转)

题目链接:http://poj.org/problem?id=3279 题目大意:有一个n*m的格子,每个格子都有黑白两面(0表示白色,1表示黑色).我们需要把所有的格子都反转成黑色,每反转一个格子,它上下左右的格子都会跟着反转.请求出用最小步数完成反转时每个格子反转的次数.有多个解时,输出字典序最小的一组. 解题思路:只要枚举第一行的2^m种情况,如果一个位置上一行是1,那这个位置一定要反转,因为只有这一行能改变上一行,所以每一行的状态都是由前一行决定的.只要最后判断最后一行是不是都是0即可,

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 状态压缩,思路 难度: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