3279POJ

给你个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;
}

你可能感兴趣的:(3279POJ)