2017sdut省赛选拔(1)--poj3279(状态压缩+枚举)

来源:互联网 发布:手机麦克风变声软件 编辑:程序博客网 时间:2024/05/30 05:10

http://poj.org/problem?id=3279

Fliptile
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 9642 Accepted: 3597

Description

Farmer John knows that an intellectually satisfied cow is a happy cow who will give more milk. He has arranged a brainy activity for cows in which they manipulate an M × N grid (1 ≤ M ≤ 15; 1 ≤ N ≤ 15) of square tiles, each of which is colored black on one side and white on the other side.

As one would guess, when a single white tile is flipped, it changes to black; when a single black tile is flipped, it changes to white. The cows are rewarded when they flip the tiles so that each tile has the white side face up. However, the cows have rather large hooves and when they try to flip a certain tile, they also flip all the adjacent tiles (tiles that share a full edge with the flipped tile). Since the flips are tiring, the cows want to minimize the number of flips they have to make.

Help the cows determine the minimum number of flips required, and the locations to flip to achieve that minimum. If there are multiple ways to achieve the task with the minimum amount of flips, return the one with the least lexicographical ordering in the output when considered as a string. If the task is impossible, print one line with the word "IMPOSSIBLE".

Input

Line 1: Two space-separated integers: M and N 
Lines 2..M+1: Line i+1 describes the colors (left to right) of row i of the grid with N space-separated integers which are 1 for black and 0 for white

Output

Lines 1..M: Each line contains N space-separated integers, each specifying how many times to flip that particular location.

Sample Input

4 41 0 0 10 1 1 00 1 1 01 0 0 1

Sample Output

0 0 0 01 0 0 11 0 0 10 0 0 0
题目大意:给出一个n*m的01矩阵,如果翻转一个位置的状态,那么与它相邻的四个方向的点也会翻转。问如何翻转才能使得矩阵全部是0.输出最小的每个点的翻转次数,如果有多组解,输出字典序最小的一个。如果无解,输出IMPOSSIBLE

题解:既然是01翻转,那么对于一个点而言的话,要么翻转1次,要么不翻转。翻转多了也没用。也就是对于一个点而言的话有两种状态翻转与不翻转。那么我先定住第一行的翻转状态,下一行也就根据该行的是0是1来确定翻与不翻。怎么定住第一行的状态呢。暴力枚举呗。用二进制的01来枚举第一行的状态,然后判断其他的翻转情况,最后看看是否全为1.再次提醒进行的是翻转的次数的记录。

///状态压缩找翻转状态,根据第一行的状态翻转其他的#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <queue>#include <map>using namespace std;int mp[20][20];int temp[20][20];///x,y位置的翻转次数,(只有0和1,因为翻转多了等于没翻转)int a[20][20];///最后结果int dx[]={0,0,0,1,-1};int dy[]={1,-1,0,0,0};int n,m;int judge(int x,int y)///判断(x,y)位置的颜色{    int c=mp[x][y];    for(int i=0;i<5;i++)    {        int nx=x+dx[i];        int ny=y+dy[i];        if(nx>=0&&nx<n&&ny>=0&&ny<m)            c+=temp[nx][ny];///根据周围相邻点的翻转次数和自身的颜色判断    }    return c%2;}int work(){    for(int i=1;i<n;i++)    {        for(int j=0;j<m;j++)        {            if(judge(i-1,j)==1)            {                temp[i][j]=1;///如果上一行的j位置为1那么就翻转i,j            }        }    }    for(int i=0;i<m;i++)    {        if(judge(n-1,i)==1)        {            return -1;///判断最后一行是否全是0        }    }    int cnt=0;    for(int i=0;i<n;i++)    {        for(int j=0;j<m;j++)        {            cnt+=temp[i][j];///充计在这个状态下的翻转次数        }    }    return cnt;}int main(){    while(~scanf("%d%d",&n,&m))    {        for(int i=0;i<n;i++)        {            for(int j=0;j<m;j++)            {                scanf("%d",&mp[i][j]);            }        }        int res=-1;        for(int i=0;i<(1<<m);i++)        {            memset(temp,0,sizeof(temp));            for(int j=0;j<m;j++)            {                temp[0][m-j-1]=(i>>j)&1;            }            int num=work();            if(num!=-1&&(res==-1||num<res))            {                res=num;                memcpy(a,temp,sizeof(temp));            }        }        if(res==-1)printf("IMPOSSIBLE\n");        else        {            for(int i=0;i<n;i++)            {                for(int j=0;j<m;j++)                {                    if(j==m-1)printf("%d\n",a[i][j]);                    else printf("%d ",a[i][j]);                }            }        }    }    return 0;}



0 0