给你个n*m的矩阵,0代表关灯,1代表开灯,问你按哪些位置可以让所有灯全部关闭,首先我们最开始的想法就是前一行的情况影响着后一行的情况,所以我们可以枚举第一行状态,接下来的状况就都被影响了。
我们说一下判断函数,一个位置的状态会被上下左右包括自己的影响,偶数次还是原来的状态,奇数次会与初始状态相反。一定要弄懂。:)
#include<iostream> #include<cstdio> #include<string.h> #include<string> #include<stack> #include<set> #include<algorithm> #include<cmath> #include<vector> #include<map> #include<queue> #define ll __int64 #define lll unsigned long long #define MAX 10000009 #define MAXN 2009 #define eps 1e-8 #define INF 0x7fffffff #define mod 1000000007 #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 using namespace std; //PS:http://m.blog.csdn.net/blog/u013750822/20571099 int n,m; int vis[109][109]; int mp[109][109]; int ans[109][109]; int Ans; int dir[5][2] = {0,0,0,1,1,0,0,-1,-1,0}; int solve(int x,int y)//上下左右包括自己都反转,返回x,y反转的情况,这里是难点 { int ret = mp[x][y]; for(int i = 0; i<5; i++) { int xx = x + dir[i][0]; int yy = y + dir[i][1]; if(xx>=0&&xx<m&&yy>=0&&yy<n) { ret+=vis[xx][yy]; } } return ret%2;// } int main() { //freopen("ans.txt","r",stdin); while(~scanf("%d%d",&m,&n)) { Ans = INF; for(int i = 0; i<m; i++) { for(int j = 0; j<n; j++) { scanf("%d",&mp[i][j]); } } for(int i = 0; i<(1<<n); i++) //用二进制表示第一行的反转状态 { memset(vis,0,sizeof(vis)); int res = 0; for(int j = 0; j<n; j++) { vis[0][n - j - 1] = (i>>j)&1; res+=vis[0][n - j - 1];//反转的步数 } // cout<<"TEST "<<res<<endl; // for(int i = 0; i<n; i++) // { // cout<<vis[0][i]<<" "; // } // cout<<"ENDL"<<endl; // cout<<endl; for(int j = 1; j<m; j++) { for(int k = 0; k<n; k++) { if(solve(j - 1,k))//当前反转的步数与上一行有关,如果上一行为1,则这行必须反转 { vis[j][k] = 1; res++; } } } // for(int j = 0;j<m;j++) // { // for(int i = 0;i<n;i++) // { // cout<<vis[j][i]<<" "; // } // cout<<endl; // } // cout<<"ENDL"<<endl; int flag = 1; for(int j = 0; j<n; j++) { if(solve(m - 1,j))//如果倒数第二行的 { flag = 0; break; } } if(flag&&Ans>res) { Ans = res; memcpy(ans,vis,sizeof(vis)); } } if(Ans==INF) { puts("IMPOSSIBLE"); } else { for(int i = 0; i<m; i++) { for(int j = 0; j<n; j++) { if(j) printf(" "); printf("%d",ans[i][j]); } puts(""); } } } return 0; }