POJ 3279 二进制搜索

来源:互联网 发布:如何做好酒店网络销售 编辑:程序博客网 时间:2024/06/04 19:42

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 1

0 0 0 0

题意:对于一个给定的黑白色的矩阵,奶牛每次反转可以反转一个格子和其上下左右的格子。输出最小的反转次数时的操作的矩阵表示。如果没有就输出”IMPOSSIBLE”。

思路:首先同一个格子翻转两次就能恢复原状,所以对于一个格子,多次翻转是多余的;此外翻转的格子集合相同的话,次序是无关紧要的;除了最后一行,其他任何一行上的1都可以通过下一行的翻转转换成0。

也就是说,除了最后一行外,我们总是可以通过翻转,将前n-1行翻成全0。

只要按照这样的原则:对于某一个位置x,如果它的上一个是1,就翻转它,如果是0,就不翻转。

知道了这个,我们应该就能想到,第一行的翻法直接就决定了后面的所有的翻法,这就是我们解决这道题目的思路,即枚举第一行所有可能的翻法,到了最后一行的时候如果最后一行和第一行都是白的那么明显就符合要求

//这里我们枚举第一行所有的可能情况为2的n次方,复杂度为O(n*m*2^n);

//这题的巧妙之处在于本身棋盘的状态就用0.1二进制表示,翻转的一个状态也是二进制,它们是可以相加的;

#include<stdio.h>#include<string.h>int map[22][22],mid[22][22];//mid用来做一个中间状态,可以理解为翻转的次数;int s[22][22];//存放最后的结果;int  m,n;int go[5][2]={0,0,0,1,1,0,-1,0,0,-1};//这里其实三个方向就够了int get(int x,int y){    int sum=map[x][y];//这里一定要加上他原来的状态;    for(int i=0;i<5;i++)     {    int tx=x+go[i][0];          int ty=y+go[i][1];          if(tx>=0&&tx<m&&ty>=0&&ty<n&&mid[tx][ty]!=0)             sum+=mid[tx][ty];              } return sum&1;//判断颜色;如果它的周围翻转了偶数次,说明中间态与原状态相同不需要变 ,如果为奇数则要翻转依次;}int calc(){         int i,j;     for(i=1;i<m;i++)        for(j=0;j<n;j++)         {  if(get(i-1,j)!=0)               mid[i][j]=1; } for(i=0;i<n;i++)   if(get(m-1,i)!=0)    return -1;//如果最后一行不满足,那么这种情况不满足; int ans=0;  for(i=0;i<m;i++)    for(j=0;j<n;j++)      ans+=mid[i][j];//如果满足找最小次数; return ans;}int main(){   int i,j;      while(scanf("%d%d",&m,&n)!=EOF){   for(i=0;i<m;i++)         for(j=0;j<n;j++)           scanf("%d",&map[i][j]);        int sum=-1;        for(i=0;i<1<<n;i++)//枚举第一行2的n次方的情况         {             memset(mid,0,sizeof(mid));   for(j=0;j<n;j++)            mid[0][n-j-1]=i>>j&1;//和1与判断初态,如果相同就要翻转;    int num=calc();   if(num>=0&&(sum==-1||sum>num))    {  sum=num;        for(i=0;i<m;i++)          for(j=0;j<n;j++)           s[i][j]=mid[i][j];//找最小;}     }        if(sum==-1)        {   printf("IMPOSSIBLE\n");}else{  for(i=0;i<m;i++)    {   printf("%d",s[i][0]);    for(j=1;j<n;j++)        printf(" %d",s[i][j]);        printf("\n");}}}return 0;}

1 0
原创粉丝点击