zoukankan      html  css  js  c++  java
  • poj 3279

    传送门:http://poj.org/problem?id=3279

    题面描述:

    给你一个方格,这个方格中有M*N个小方块,每个小方块都是0或1,定义一种反转操作:,每次反转范围是中心方块以及其上下左右的方块,反转后状态变化为0->1,1->0。问能不能通过有限次反转操作,将方格的最终状态变为全是0,如果可以,输出一个反转次数最少而且字典序最小的矩阵,矩阵对应的数值为该位置的反转次数,否则,输出IMPOSSIBLE。

    思路:

    1.对于同一个位置来说,最多反转1次,因为只有两种状态,反转两次事实上跟原先状态是一样的。

    2.对于同一个位置,它的最终状态会受其上下左右各个方块反转的影响,这会使问题的分析变得非常复杂,但是我们可以先确定第一行的反转次序,此时对于第一行来说,能够影响它的左中右的反转都已经确定了,那么决定他最终状态的就只有它的下的反转,调节他下面方块的反转次序,使第一行的状态全变成0,然后对于第二行一样,以此类推,到了倒数第一行,此时不仅确定了倒数第二行的状态,也把最后一行的反转次数确定了,同时,最后一行的状态也被确定了(可能有点绕),此时我们只要判断最后一行是不是全是0就可判断这种第一行的反转次序是不是可以满足条件。

    3.接下来,我们来思考如何来枚举第一行的各种反转次数,由1可以知道,每个位置事实上只有0和1两种状态,所以我们可以考虑二进制枚举来解决问题,具体实现在AC代码里面。因为我们是从小到大枚举的,所以最终得到的结果一定是最小字典序的,所以不用再考虑字典序的问题了。

    最终代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn = 20;
    int map[maxn][maxn],flip[maxn][maxn],ans[maxn][maxn],m,n;
    int dx[]  = {1,0,0,0,-1};
    int dy[] = {0,1,0,-1,0};
    int get(int x,int y){
        int c =map[x][y];
        for(int d = 0;d<5;d++){
            int x1 = x+dx[d];
            int y1 = y+dy[d];
            if(x1>=0&&x<m&&y>=0&&y<n){
                c+=flip[x1][y1];
            }
        }
        return c%2;
    }
    int calc(){
        int res = 0;
        for(int i = 1;i<m;i++)
            for(int j = 0;j<n;j++)
            {
                if(get(i-1,j))
                {
                    flip[i][j] = 1;
                }
            }
        for(int i = 0;i<n;i++)
            if(get(m-1,i)!=0)
                return -1;
        for(int i = 0;i<m;i++)
            for(int j = 0;j<n;j++)
                res+=flip[i][j];
        return res;
    }
    int main()
    {
        while(~scanf("%d %d",&m,&n)){
            for(int i = 0;i<m;i++)
                for(int j = 0;j<n;j++)
                    scanf("%d",&map[i][j]);int res = -1;
            for(int i = 0;i< 1<< n;i++){
                
                memset(flip,0,sizeof(flip));
                for(int j = 0;j<n;j++)
                    flip[0][n-j-1] =  i>>j&1;
                int num = calc();
                if(num>=0&&(res<0||res>num)){
                    res = num;
                    memcpy(ans,flip,sizeof(flip));
                }
            }
            if(res==-1)
                printf("IMPOSSIBLE
    ");
            else
            {
                for(int i = 0;i<m;i++)
                    for(int j = 0;j<n;j++)
                        printf("%d%c",ans[i][j],j+1==n?'
    ':' ');
            }
        }
        return 0;
    }

    如还有困惑的地方,请在评论区留言交流!

  • 相关阅读:
    java io系列23之 BufferedReader(字符缓冲输入流)
    java io系列22之 FileReader和FileWriter
    java io系列21之 InputStreamReader和OutputStreamWriter
    java io系列20之 PipedReader和PipedWriter
    java io系列19之 CharArrayWriter(字符数组输出流)
    java io系列18之 CharArrayReader(字符数组输入流)
    java io系列17之 System.out.println("hello world")原理
    java io系列16之 PrintStream(打印输出流)详解
    java io系列15之 DataOutputStream(数据输出流)的认知、源码和示例
    java io系列14之 DataInputStream(数据输入流)的认知、源码和示例
  • 原文地址:https://www.cnblogs.com/baihualiaoluan/p/10964444.html
Copyright © 2011-2022 走看看