zoukankan      html  css  js  c++  java
  • POJ:3279-Fliptile(矩阵反转)

    Fliptile

    Time Limit: 2000MS Memory Limit: 65536K
    Total Submissions: 14701 Accepted: 5381

    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 they manipulate an M × N grid (1 ≤ M ≤ 15; 1 ≤ N ≤ 15) of square tiles, each of which is colored black on one side and white on the other side.

    As one would guess, when a single white tile is flipped, it changes to black; when a single black tile is flipped, it changes to white. The cows are rewarded when they flip the tiles so that each tile has the white side face up. However, the cows have rather large hooves and when they try to flip a certain tile, they also flip all the adjacent tiles (tiles that share a full edge with the flipped tile). Since the flips are tiring, the cows want to minimize the number of flips they have to make.

    Help the cows determine the minimum number of flips required, and the locations to flip to achieve that minimum. If there are multiple ways to achieve the task with the minimum amount of flips, return the one with the least lexicographical ordering in the output when considered as a string. If the task is impossible, print one line with the word “IMPOSSIBLE”.

    Input

    Line 1: Two space-separated integers: M and N
    Lines 2..M+1: Line i+1 describes the colors (left to right) of row i of the grid with N space-separated integers which are 1 for black and 0 for white

    Output

    Lines 1..M: Each line contains N space-separated integers, each specifying how many times to flip that particular location.

    Sample Input

    4 4
    1 0 0 1
    0 1 1 0
    0 1 1 0
    1 0 0 1

    Sample Output

    0 0 0 0
    1 0 0 1
    1 0 0 1
    0 0 0 0


    解题心得:

    1. 题意就是给你一个矩阵,你可以选择一个里面的数进行0-1反转,在反转的同时,和这个数相邻的四个方向(上下左右)的数也会跟着0-1反转,现在叫你输出一个选择数反转的方案出来,要求反转次数最少。
    2. 如果进行枚举,可能性为2^(n*m),太大了。可以明确的一点是,反转的顺序对于结果是没有影响的,有影响的只是反转的次数。所以如果我们规定一个从上到下的反转顺序,那么第一排如果能够确定,根据第一排的结果第二排也能确定,就可以得到答案了。但是如何确定第一排呢,只有枚举,将第一排所有的情况枚举出来,然后在第一排已知的情况下向下推,去计算整个矩阵。复杂度为O(n*m(2^n)),这个复杂度是可以接受的。

    #include <algorithm>
    #include <stdio.h>
    #include <cstring>
    #include <climits>
    using namespace std;
    const int maxn = 20;
    
    int dir[5][2] = {1,0,0,1,0,0,-1,0,0,-1};
    int flip[maxn][maxn],opt[maxn][maxn];//opt用来存放最后反转的操作,flip用来存放当前的反转操作
    int tile[maxn][maxn],n,m;//
    
    void init() {//tile用来储存原矩阵
        scanf("%d%d",&m,&n);
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
                scanf("%d",&tile[i][j]);
    }
    
    bool check(int x,int y) {//检查是否超出了矩阵的范围
        if(x < 0 || y < 0 || x >= m || y >= n)
            return true;
        return false;
    }
    
    bool get(int x,int y) {//检验同一列上一行的这个位置是否需要反转
        int cnt = tile[x][y];
        for(int i=0;i<5;i++) {
            int xx = x + dir[i][0];
            int yy = y + dir[i][1];
    
            if(check(xx,yy))
                continue;
            cnt += flip[xx][yy];
        }
        if(cnt%2)
            return true;
        return false;
    }
    
    int cal() {
        int cnt = 0;
        for(int i=1;i<m;i++) {
            for(int j=0;j<n;j++) {
                if(get(i-1,j))
                    flip[i][j] = 1;//如果需要反转做好标记
            }
        }
        for(int i=0;i<n;i++) {
            if(get(m-1,i))//检验最后一行是否符合条件
                return -1;
        }
    
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++) {
                if(flip[i][j])
                    cnt++;
            }
        return cnt;
    }
    
    int solve() {
        int res = INT_MAX;
        for(int i=0;i<(1<<n);i++) {//枚举第一行
            memset(flip,0,sizeof(flip));
            for(int j=n-1;j>=0;j--)
                flip[0][j] = (i >> j) & 1;
            int num = cal();
            if(num > 0 && res > num) {
                res = num;
                memcpy(opt,flip,sizeof(flip));
            }
        }
        return res;
    }
    
    void Print() {
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++) {
                printf("%d%c",opt[i][j],j == n-1 ? '
    ' : ' ');
            }
    }
    
    int main() {
        init();
        int ans = solve();
        if(ans == INT_MAX) {
            printf("IMPOSSIBLE
    ");
            return 0;
        }
        Print();
        return 0;
    }
  • 相关阅读:
    C#实现断点续传
    记住密码"功能的正确设计
    异常处理的性能开销
    asp.net提高程序性能的技巧(一)
    C#创建文件夹
    一个商人应遵守的22条规矩
    列不属于表--可能出现的问题总结
    存储过程无法得到返回型参数
    通用存储过程(增、删、改、查询分页)
    Mac下使用Charles抓包https接口
  • 原文地址:https://www.cnblogs.com/GoldenFingers/p/9107106.html
Copyright © 2011-2022 走看看