kuangbin专题里面比较骚的一道题目 直接暴力枚举会超时 但是仔细想会发现两个规律 第一 不存在一个位置修改的次数大于1 第二 修改的顺序是无所谓的 那么我们可以一行一行往下操作 假设对于每一行我们都是按照一种绝对正确的方式去绝对翻和不翻的话 那么对于下面的某个坐标(x,y)必有 若(x-1,y)为1则翻 否则一定不翻 因此我们可以枚举第一行的所有操作可能 以下几行的所有坐标按上面的逻辑法则进行操作 最后判断最后一行是否被翻
#include <stdio.h> #include <iostream> #include <vector> #include <math.h> #include <algorithm> #include <queue> #include <string.h> using namespace std; int g[17][17]; //保存初始状态 int f[17][17] = {}; int ans[17][17] = {}; int mmin = 0x1f1ffff; bool judge(int n,int m)//判断最后一行是否全为0 { for(int i=1;i<=m;i++) { int t = f[n][i]+f[n][i-1]+f[n][i+1]+f[n-1][i]; if((g[n][i]+t)&1) return false; } return true; } void fun(int n, int m, int num) { for(int i=2;i<=n;i++) { for(int j=1;j<=m;j++) { if(num > mmin) return; if((g[i-1][j]+f[i-2][j]+f[i-1][j-1]+f[i-1][j+1]+f[i-1][j])&1)//上一行是否为1,即是否需要翻转 { f[i][j] = 1; ++num; } else f[i][j] = 0; } } if(judge(n, m) && mmin>num)//判断是否符合条件 { memcpy(ans, f, sizeof(f)); mmin = num; } } int main() { int n,m; cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)//下标从1开始,便于边界处理 cin>>g[i][j]; for(int i=0;i < 1<<(m+1);i++) { int num = 0; for(int j=1;j<=m;j++) { f[1][j] = i>>(m-j+1) & 1; num += f[1][j]; } fun(n, m, num); } if(mmin == 0x1f1ffff) cout<<"IMPOSSIBLE"<<endl; else for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) cout<<ans[i][j]<<" "; cout<<endl; } return 0; }