zoukankan      html  css  js  c++  java
  • POJ 3279

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

    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

    题意:

    给出 $M$ 行 $N$ 的矩阵,每个元素只为 $0$ 或者 $1$,分别代表白块和黑块,

    每次可以翻转一个元素,使得它可以从黑变白或者从白变黑,但是上下左右相邻的四个元素也会跟着翻转,

    求最少翻转多少个元素,可以使得全部元素均变成 $0$。

    给出需要反转的元素,若有多个答案,给出字典序最小的,若无答案,输出"IMPOSSIBLE"。

    题解:

    首先,显然的:翻转只有 $0$ 次和 $1$ 次,多了没用;其次,翻转顺序无关性,结果与翻转方块的顺序无关,只与翻转那几个方块有关。

    如果从上往下一行一行看,那么当第 $i$ 行确定了如何翻转后,第 $i$ 行上如果剩下来若干个黑块,那么只能靠翻转第 $i+1$ 行来将其变成白块,

    这就注定了:一旦确定了第 $1$ 行如何翻转,后面的所有行如何翻转都被确定。

    所以只要枚举第 $1$ 行所有翻转方案即可,列数不超过15,可以使用状压。

    另外,由于第一行的翻转方案一旦给定,后面三行就是固定的,所以翻转方案的字典序可以只看第一行,

    所以方案可以存成一个结构体,在存储方案数组的同时,一并存储总的翻转次数,以及,第一行翻转方案(存成二进制数);在最后进行排序,并输出第一个即可。

    AC代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    using namespace std;
    
    const int maxn=18;
    
    int m,n;
    int mp[maxn][maxn],tmp[maxn][maxn];
    
    struct Ans{
        int idx;
        int times;
        int f[maxn][maxn];
        Ans()
        {
            this->times=0;
            memset(f,0,sizeof(f));
        }
    };
    bool cmp(Ans a,Ans b)
    {
        if(a.times==b.times) return a.idx<b.idx;
        return a.times<b.times;
    }
    
    inline void flip(int i,int j)
    {
        if(i>1) tmp[i-1][j]^=1;
        if(i<m) tmp[i+1][j]^=1;
        if(j>1) tmp[i][j-1]^=1;
        if(j<n) tmp[i][j+1]^=1;
        tmp[i][j]^=1;
    }
    
    inline bool allwhite()
    {
        for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) if(tmp[i][j]) return 0;
        return 1;
    }
    
    int main()
    {
        cin>>m>>n;
        for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) cin>>mp[i][j];
    
        vector<Ans> v;
        for(int sta=0;sta<(1<<n);sta++)
        {
            for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) tmp[i][j]=mp[i][j];
    
            Ans ans;
            for(int j=1;j<=n;j++) if(sta&(1<<(n-j))) flip(1,j), ans.f[1][j]=1, ans.times++;
            for(int i=2;i<=m;i++) for(int j=1;j<=n;j++) if(tmp[i-1][j]) flip(i,j), ans.f[i][j]=1, ans.times++;
            if(allwhite())
            {
                ans.idx=sta;
                v.push_back(ans);
            }
        }
        sort(v.begin(),v.end(),cmp);
        if(v.size()>0) for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) printf("%d%c",(*v.begin()).f[i][j],j<n?' ':'
    ');
        else printf("IMPOSSIBLE
    ");
    }

    时间复杂度:$Oleft( {2^n mn} ight)$;后面的对所有可行方案的排序,认为能够达成目标的翻转方案远小于 $2^n$,不考虑其时间复杂度)。

  • 相关阅读:
    hdu1865 1sting (递归+大数加法)
    hau1021 Fibonacci Again(递归)
    hdu2553 N皇后问题(dfs+回溯)
    BZOJ2342 [Shoi2011]双倍回文 【manacher】
    Manacher算法学习 【马拉车】
    BZOJ2743 [HEOI2012]采花 【离线 + 树状数组】
    BZOJ1296 [SCOI2009]粉刷匠 【dp】
    BZOJ1086 [SCOI2005]王室联邦 【dfs + 贪心】
    BZOJ1565 [NOI2009]植物大战僵尸 【最大权闭合子图 + tarjan缩点(或拓扑)】
    BZOJ2157 旅游 【树剖 或 LCT】
  • 原文地址:https://www.cnblogs.com/dilthey/p/9690982.html
Copyright © 2011-2022 走看看