Fliptile POJ - 3279 开关反转问题 + 位运算

解这题的关键思想

第一行的状态决 定了后面所有行的状态

奶牛踏瓷砖问题,显然奶牛踏 1 次和奶牛踏3次,效果是一样的,那么每块瓷砖的翻转次数,只可能是 0次或一次。

那么现在问题就转换成了枚举结果矩阵中的每一个数值是 1 还是0 ,但是 M 和 N 的最大值为 15,单纯暴力的话,2^15*15 一定会超时。

问题的关键在于前一行的状态决定了后一行的状态,所以一旦第一行确定,后面的所有行就确定了。现在就可以转化成单纯的枚举每一行或者每一列。 时间复杂度 2^15 ,很小。

起始状态                                          踏瓷砖次数矩阵
1 0 0 1                                              0 0 0 0
0 1 1 0                                              1 0 0 1
0 1 1 0                                              1 0 0 1
1 0 0 1                                              0 0 0 0

我实现的代码就是 枚举第一列的状态 ,计算出踏瓷砖的状态矩阵,判断最后该情况是否可取,因为照这种前一列推后一列的状态,最后一列的状态不一定是全0,所以要判断一下。

代码如下:

#include<iostream>
#include<cstring>

using namespace std;
int statu[20];
int m,n;
int maze[20][20];
int result[20][20];   //存储最终结果
int mid[20][20];      //存储枚举的结果
int mid_maze[20][20]; //存储中间变化的迷宫
int dir[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int max_time;
void flip(int x,int y)
{
    mid_maze[x][y]  = (mid_maze[x][y]+1)%2;

    for(int i=0;i<4;i++)
    {
        int px =x+dir[i][0];
        int py = y+dir[i][1];
        if(px<0||py<0||px>=m||py>=n) continue;
        mid_maze[px][py]  = (mid_maze[px][py]+1)%2;
    }
}
int hasre;
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>m>>n)
    {
        hasre=0;
        memset(mid_maze,0,sizeof(mid_maze));
        memset(maze,0,sizeof(maze));

        max_time = 0x3f3f3f3f;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                cin>>maze[i][j];
            }
        }

        for(int pp=0; pp< 2<<n;pp++)
        {

                int counts = 0;
                int p =pp;
                memset(statu,0,sizeof(statu));
                memset(mid,0,sizeof(mid));

                while(p!=0)
                {
                    statu[counts++] = p&1;
                    p = p>>1;
                }


                for(int i=0;i<m;i++)
                    for(int j=0;j<n;j++)
                        mid_maze[i][j] = maze[i][j];

                counts =0;
                for(int i=0;i<n;i++)
                {
                    mid[0][i] = statu[i];
                    if(statu[i])
                    {
                        flip(0,i);
                        counts++;
                    }
                }

                for(int i=1;i<m;i++)
                {
                    for(int j=0;j<n;j++)
                    {
                        if(mid_maze[i-1][j] ==1)
                        {
                            mid[i][j]=1;
                            flip(i,j);
                            counts++;
                        }
                    }
                }
                int ops=1;
                for(int i=0;i<n;i++)
                {
                    if(mid_maze[m-1][i]==1)
                    {
                        ops=0;
                        break;
                    }
                }

                if(ops==0)continue;

                if(counts < max_time)
                {
                    max_time = counts;
                    hasre=1;
                    for(int i=0;i<m;i++)
                    {
                        for(int j=0;j<n;j++)
                        {
                            result[i][j] = mid[i][j];
                        }
                    }
                }else if(counts == max_time){

                    int flag=0;
                    for(int i=0;i<m;i++)
                    {
                        for(int j=0;j<n;j++)
                        {
                            if(result[i][j] > mid[i][j])
                            {
                                break;
                                flag=1;
                            }
                        }
                        if(flag==1)break;
                    }

                    if(flag ==1)
                    {
                        hasre =1;
                        for(int i=0;i<m;i++)
                        {
                            for(int j=0;j<n;j++)
                            {
                                result[i][j] = mid[i][j];
                            }
                        }
                    }


                }

        }
        if(hasre ==0)
        {
            cout<<"IMPOSSIBLE"<<endl;
            continue;
        }


        for(int i=0;i<m;i++)
        {
            cout<<result[i][0];
            for(int j=1;j<n;j++)
            {
                cout<<" "<<result[i][j];
            }
            cout<<endl;
        }


    }
    return 0;
}

最后附上一个网上大牛用该题写的小游戏
https://pan.baidu.com/s/1czj69yuvMVf_b7IbSOm-ig

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值