题意:点击一个点,则这个点和上下左右共五个点都会翻转。问最少点几个点可以使地图全是 0。
思路:枚举第一行所有可能的情况,第一行若有 1 的话必须翻转下一行对应位置才可以满足条件,以此类推,最后判断最后一行是否满足条件。
#include<iostream> #include<cmath> #include<queue> #include<cstring> #include<string> #include<cstdio> #include<algorithm> using namespace std; int m, n; int pic[20][20]; int flip[20][20]; //当前解 int ans[20][20]; //最优解 int dir[5][2]{-1, 0, 1, 0, 0, 0, 0, 1, 0, -1}; //五个点 int judge(int x, int y){ //通过这个点被翻动的次数判断这个点是否为黑 int a = pic[x][y]; for(int i = 0; i < 5; i++){ int x1 = x + dir[i][0]; int y1 = y + dir[i][1]; if(x1 >= 0 && y1 >= 0 && x1 <m && y1 < n) a += flip[x1][y1]; } return a&1; } int cal(){ for(int i = 1; i < m; i++){ for(int j = 0; j < n; j++){ if(judge(i-1, j)) //如果这个点是1 flip[i][j] = 1; //翻转这个点下一行对应的点 } } for(int i = 0; i < n; i++) //验证最后一行是否满足条件 if(judge(m-1, i)) return 0x7fffffff; int cnt = 0; //本次情况的翻转次数cnt for(int i = 0; i < m; i++) for(int j = 0; j < n; j++) if(flip[i][j]) cnt++; return cnt; } int main(){ //freopen("a.txt", "r", stdin); while(scanf("%d %d", &m, &n) != EOF){ for(int i = 0; i < m; i++) for(int j = 0; j < n; j++) scanf("%d", &pic[i][j]); int cnt = 0x7fffffff; for(int i = 0; i < (1<<n); i++){ //第一行共2^n种情况 memset(flip, 0, sizeof(flip)); for(int j = 0; j < n; j++) flip[0][j] = (i>>j)&1; //每种情况中,第一行的n个数 int temp = cal(); //求解这种情况的答案 if(temp < cnt){ //比较 cnt = temp; for(int i = 0; i < m; i++) for(int j = 0; j < n; j++) ans[i][j] = flip[i][j]; } } if(cnt == 0x7fffffff) cout << "IMPOSSIBLE" << endl; else{ for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ if(j) cout << " "; cout << ans[i][j]; } cout <<endl; } } } return 0; }