标签:poj
题意:
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比赛的时候没有出...被虐成马
poj 3279 Filptile (USACO 2007 Open Silver)
标签:poj
原文地址:http://blog.csdn.net/u013382399/article/details/45036443