POJ - 3279 Fliptile(反轉)

題意:一個01矩陣,每翻轉一個格子,這個格子的上下左右的格子都會被翻轉,要把整個矩陣的格子都翻轉爲0,求需要翻轉的最小次數,最小次數的解爲多個時,輸出字典序最小的一組。解不存在輸出IMPOSSIBLE。

思路:如果暴力搜索的話有2^{nm}種翻轉的方法,超時。如果第一行是否翻轉已經確定,那麼第二行是否翻轉也確定了,同理除了最後一行其餘所有的格子是否翻轉都已確定了,如果最後一行有1的話就說明不存在可行解。所以我們可以枚舉第一行是否翻轉的情況,對於每一種情況找可行解,求翻轉最小次數,時間複雜度2^{n}nm

#include <stdio.h>
#include <string.h>
int flip[20][20],c[20][20],op[20][20];
int to[5][2] = {1,0,-1,0,0,1,0,-1,0,0};
int n,m;
int get(int x,int y)
{
    int i,num,tx,ty;
    num = c[x][y];
    for(i = 0; i < 5; i++) {
        tx = x + to[i][0];
        ty = y + to[i][1];
        if(tx >= 0 && ty >= 0 && tx < n && ty < m)
            num += flip[tx][ty];
    }
    return num % 2;
}
int calc()
{
    int i,j,res;
    for(i = 1; i < n; i++) {
        for(j = 0; j < m; j++) {
            if(get(i - 1,j))
                flip[i][j] = 1;
        }
    }
    res = 0;
    for(i = 0; i < m; i++)
        if(get(n - 1,i))
            return -1;
    for(i = 0; i < n; i++) {
        for(j = 0; j < m; j++) {
            res += flip[i][j];
        }
    }
    return res;
}
int main(void)
{
    int i,j,res,num;
    scanf("%d %d",&n,&m);
    for(i = 0; i < n; i++) {
        for(j = 0; j < m; j++) {
            scanf("%d",&c[i][j]);
        }
    }
    res = -1;
    for(i = 0; i < (1 << m); i++) {
        memset(flip,0,sizeof(flip));
        for(j = 0; j < m; j++) {
            flip[0][m - j - 1] = i >> j & 1;
        }
        num = calc();
        if(num >= 0 && (res < 0 || res > num)) {
            res = num;
            memcpy(op,flip,sizeof(flip));
        }
    }
    if(res < 0)
        printf("IMPOSSIBLE\n");
    else {
        for(i = 0; i < n; i++) {
            for(j = 0; j < m; j++) {
                if(j == 0) printf("%d",op[i][j]);
                else printf(" %d",op[i][j]);
            }
            printf("\n");
        }
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章