poj 3279 Filptile (USACO 2007 Open Silver)

题意:

n*m块区域,每一块有正反两面,两面分别是白色和黑色。

翻转一块区域的同时, 与其相邻的四块区域也会同时被反转 

问最少需要翻转的次数 ,使所有的区域都变成白色 输出其翻转方案 

思路:

枚举第一行的翻转状态

如果已经知道了第一行的状态,那么后面几行的状态就随之确定了——(如果该区域的上面一个区域是黑色,那这个区域必然是要反转才能让他上面的区域变成白色)

然后比较和记录最少的翻转次数 输出即可

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn = 20;
const int INF = 0x3f3f3f3f;

int maze[maxn][maxn], tmaze[maxn][maxn];
int ans[maxn][maxn], min_ans[maxn][maxn];
int n,m;


void deal(int x, int y){
    tmaze[x][y] ^= 1;
    tmaze[x+1][y] ^= 1;
    tmaze[x-1][y] ^= 1;
    tmaze[x][y+1] ^= 1;
    tmaze[x][y-1] ^= 1;
}
void deal1(int s){
    int cnt = m;
    for(int i = 0; i < m; i++){
        ans[1][cnt--] = (s>>i)&1;
    }
}
bool deal2(){
    for(int i = 1; i <= m; i++){
        if(ans[1][i] == 1){
            deal(1,i);
        }
    }
    for(int i = 2; i <= n; i++){
        for(int j = 1; j <= m; j++){
            if(tmaze[i-1][j] == 1){
                ans[i][j] = 1;
                deal(i,j);
            }
        }
    }
    bool flag = true;
    for(int i = 1; i <= m; i++){
        if(tmaze[n][i] != 0){
            flag = false;
        }
    }
    return flag;
}
void init(){
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            scanf("%d",&maze[i][j]);
        }
    }
}
void solve(){
    bool flag;
    bool flag2 = false;
    int min_ = INF;
    memset(min_ans, 0, sizeof(min_ans));
    for(int s = 0; s < (1<<m); s++){
        memset(ans, 0, sizeof(ans));
        memcpy(tmaze, maze, sizeof(maze));
        deal1(s);//获取第一行状态 放到ans[1][i] 中

        flag = deal2();//依据第一行进行翻转
        if(flag){//成功 则输出
            flag2 = true;
            int tmp = 0;
            for(int i = 1; i <= n; i++){
                for(int j = 1; j <= m; j++){
                    if(ans[i][j] == 1) tmp++;
                }
            }
            if(tmp < min_){
                memcpy(min_ans, ans, sizeof(ans));
                min_ = tmp;
            }
        }
    }
    if(!flag2)
        printf("IMPOSSIBLE\n");
    else{
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                if(j != 1) printf(" ");
                printf("%d",min_ans[i][j]);
            }
            printf("\n");
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    init();
    solve();
    return 0;
}



虽然这道题目起码做过3回了,但还是不记得怎么做的....简直无情T_T比赛的时候没有出...被虐成马



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值