POJ3279【枚举】

来源:互联网 发布:g76螺纹编程实例 编辑:程序博客网 时间:2024/05/30 04:39
#include<stdio.h>#include<string.h>int map[16][16], dp[16][16], an[16][16];int n, m, dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};bool isflip(int x, int y){int i, cnt = dp[x][y];//本来翻转的次数 for(i = 0; i < 4; ++i){int nx = x+dx[i];int ny = y+dy[i];if(nx < 0 || nx >= n || ny < 0 || ny >= m)continue;cnt += dp[nx][ny];//加上四周的点翻转的次数 }cnt += map[x][y];// 加上该点原来的状态 return cnt&1;//如果是奇数  则需要翻转 }int check(){int i, j;for(i = 1; i < n; ++i)for(j = 0; j < m; ++j)if(isflip(i-1, j))//是否需要翻转 dp[i][j] = 1;for(i = 0; i < m; ++i)if(isflip(n-1,i))//如果最后一行有1则失败 return -1;int ans = 0;for(i = 0; i < n; ++i)for(j = 0; j < m; ++j)ans += dp[i][j];return ans;}int main(){int i, j, k;while(scanf("%d%d", &n, &m) != EOF){for(i = 0; i < n; ++i)for(j = 0; j < m; ++j)scanf("%d", &map[i][j]);//枚举第一行的情况int cas = 1 << m;int ans = 100000000; for(i = 0; i < cas; ++i)//每一个i代表第一行的一种翻转情况 {//对于每一个i进行暴力翻转//如果最后一行全部翻转成功记录翻转的最小次数//同时记录翻转后的状态 memset(dp, 0, sizeof(dp));for(j = 0; j < m; ++j)if(i & (1<<j))dp[0][j] = 1;int temp = check();if(temp == -1)continue;else{if(temp < ans){ans = temp;memcpy(an, dp, sizeof(dp));}}} if(ans == 100000000)printf("IMPOSSIBLE\n");else{for(i = 0; i < n; ++i)for(j = 0; j < m; ++j){if(j != m-1)printf("%d ", an[i][j]);elseprintf("%d\n", an[i][j]);}}}return 0;}

题意:给出一个二维矩阵,每个点要么是0要么是1,现在对其中一个点进行翻转,那么这个点四周的点也会随之翻转,现在问最少翻转多少次能将该矩阵翻转为全0 的状态,如果不行则输出IMPOSSIBLE,若可以则输出每个点翻转的次数。

思路:对于二维的矩阵,我们列举第一行的所有情况,因为要求所有状态都为0, 所以当第一行状态确定时,第二行也就随之确定了,以此类推到最后一行,若最后一行状态全为0,则可以保存翻转的次数,若是比先前的小,则要保存当前每个点翻转的次数。最后输出结果。

0 0