zoukankan      html  css  js  c++  java
  • POJ 3279 Flip title 状态压缩+暴力

    POJ 3279 Flip title 状态压缩+暴力

    题意

    (M*N) (<=15)的01矩阵,定义操作(f[i][j]):使第i行j列的元素自身以及上下左右共五个格子翻转,找出翻转次数最少的方案,如果有多个解,输出字典序最小的方案

    题目链接

    思路

    N的范围只有15,构造状态数组(r[M]),其值为矩阵每一行的状态,比如样例输入第一行1001,就可以将其表示为1001(2) = 9。定义操作矩阵(b[M]),表示翻转对应位,比如0001(2) = 1,表示第1,2,3位不翻转,第四位翻转。

    枚举第一行的(2^n)种情况,对第一行进行操作后,依次处理其他行,每次将其上面一行变为全0,处理完毕后如果最后一行也为0,则得到一个解。

    显然,对于(a[i][j]=1), 我们只需要令(b[i+1][j]=1), 就能让(a[i])的1被翻转成0。设第(i)行为(a_i) 则对第(i+1)行需要进行的操作就是(a_i) ,我们只要把路径最小的(a_i)存起来,因为我们是按照字典序枚举的,所以找到的第一个解就是(Ans)

    以下给出用位运算压缩的解法,作为比较,数组解法的时间消耗要远大于位运算,实测中大约在3倍时间差距左右。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    const int MAX = 15 + 5;
    int n, m;
    int r[MAX];    //原始矩阵
    int a[MAX];    //临时矩阵
    int b[MAX];    //操作矩阵
    int ans[MAX];  //结果矩阵
    int cnt;
    void flip(int i, int j) {  //对a[i][j]翻转
        cnt++;
        a[i] ^= 1 << j;
        a[i] ^= 1 << (j - 1);
        a[i] ^= 1 << (j + 1);
        a[i + 1] ^= 1 << j;
        a[i - 1] ^= 1 << j;
    }
    void solve(int i, int x) {  //对a[i]进行操作x
        b[i] = x;
        for (int j = 1; j <= m; j++) {
            if (x & (1 << j)) {
                flip(i, j);
            }
        }
    }
    int main(void) {
        while (scanf("%d%d", &n, &m) != EOF) {
            memset(a, 0, sizeof(a));
            memset(b, 0, sizeof(b));
            memset(r, 0, sizeof(r));
            int t;
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= m; j++) {
                    scanf("%d", &t);
                    if (t) {
                        r[i] |= 1 << j;  //对应位置1
                    }
                }
            }
            int len = INF;
            int bound = 1 << m;
            for (register int state = 0; state < bound; state++) {
                cnt = 0;
                for (int i = 1; i <= n; i++) {
                    a[i] = r[i];
                }
                int i = state << 1;  //做了一个偏移
                solve(1, i);
                for (int j = 2; j <= n; j++) {
                    solve(j, a[j - 1]);
                }
                int flag = (a[n] >> 1) % bound;  //去掉偏移量
                if (cnt < len && !flag) {
                    len = cnt;
                    for (int k = 1; k <= n; k++) {
                        ans[k] = b[k];
                    }
                }
            }
            if (len == INF) {
                printf("IMPOSSIBLE
    ");
            } else {
                for (int i = 1; i <= n; i++) {
                    printf("%d", ans[i] & (1 << 1) ? 1 : 0);
                    for (int j = 2; j <= m; j++) {
                        printf(" %d", ans[i] & (1 << j) ? 1 : 0);
                    }
                    printf("
    ");
                }
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    POJ
    POJ
    操作系统
    POJ
    POJ
    codeforces Educational Round 89
    codeforces Round 647(div. 2)
    codeforces Educational Round 88
    后缀自动机简单总结
    dsu on tree 简单总结
  • 原文地址:https://www.cnblogs.com/hermitgreen/p/12561554.html
Copyright © 2011-2022 走看看