//采用了大佬的题解,由于移动某一枚棋子上下左右中,上只有一个,所以将当前行作为上一定能移动到想要的效果。 //但是这样的话虽然合理,但是对于第一行没有进行任何的移动,这样会失去一些情况导致失败。所以将第一行上面再加一行 //从而让第一行有枚举移动的可能性,所以对于新加的第一行需要通过状态压缩DP使用01位运算枚举所有的可能性 //然后在最后统一的是0还是1这两个当中同样进行两次枚举。每次枚举的结果挑选最小值即可 #include <iostream> #include <cstdio> #include <cmath> #include <limits.h> #define ll long long #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) using namespace std; const int MAXN = 101; const int MAXM = 11; ll a[MAXN][MAXM], A[MAXN][MAXM]; int n, m; //进行上下左右以及自身的翻转 void reverses(int x, int y) { int i=0; //提供移动的数组 int y1[6] = {0, 0,0, -1, 1}; int x1[6] = {0, 1, 2,1, 1}; for (i;i<6;i++) { if (x+x1[i]>=0&&x+x1[i]<n&&y+y1[i]>=0&&y+y1[i]<m) { a[x+x1[i]][y+y1[i]] = a[x+x1[i]][y+y1[i]]==0? 1:0; } } } ll get_num(int i, int target) { ll step = 0; for (int j=0;j<n;j++) { for (int k=0;k<m;k++) { a[j][k] = A[j][k]; } } //对新加的第一行进行统一,也就是将原先第一行进行一个调整 for (int j=0;j<m;j++) { if (i&(1<<j)) { step++; reverses(-1, j); } } // for (int j=0;j<n-1;j++) { for (int k=0;k<m;k++) { if (a[j][k]!=target) { step++; reverses(j, k); } } } for (int k=0;k<m;k++) { if (a[n-1][k]!=target) { return INT_MAX; } } return step; } int main() { // IOS; ll ans = INT_MAX-1; cin>>n>>m; for (int i=0;i<n;i++) { for (int j=0;j<m;j++) { scanf("%1d", &A[i][j]); } } for (int i=0;i<(1<<m);i++) { ans = min(ans, get_num(i, 1));//全部变成1的情况 ans = min(ans, get_num(i, 0));//全部变成0的情况 } if (ans == INT_MAX-1) { cout<<"Impossible"; return 0; } cout<<ans; return 0; }