D - Fliptile

Posted jiaqi666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了D - Fliptile相关的知识,希望对你有一定的参考价值。

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 4
1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1

Sample Output



题意:类似矩阵翻硬币的题,题目给了一个M*N的二进制矩阵,可以选择任意一个点将它翻转,同时和它相邻的(上下左右)位置都需要翻转,找出一种翻转次数最少的方案,输出一个M*N的矩阵,每个位置的值代表其翻转次数
思路:枚举第一排的灯按与不按的方案(用搜索或者位运算),然后从i=1开始从左到右遍历,如果(i-1,j)灯没关,那么(i,j)就需要进行翻转

有个坑磨了我好久,可能有好几种最优方案,比如给的样例其实还有一种最优解法是:
0 1 1 0
0 0 0 0
0 0 0 0
0 1 1 0
但是题目只要最后一个最优方案

#include <iostream>
#include <cstring>  
/* 经典的开关灯问题,题目给了一个M*N的二进制矩阵,可以选择任意一个点将它翻转,同时和它相邻的(上下左右)位置都需要翻转,
找出一种翻转次数最少的方案,输出一个M*N的矩阵,每个位置的值代表其翻转次数 */

//思路:枚举第一排的灯按与不按的方案(用搜索或者位运算),如果第一排还有灯没关(i,j),那么下一排(i-1,j)就需要进行翻转 

//数据范围:(1 ≤ M ≤ 15; 1 ≤ N ≤ 15) 
 
using namespace std;
#define MAX 20
int Matri[MAX][MAX];  //灯矩阵
int cp[MAX][MAX];  //复制灯矩阵
int temp[MAX][MAX];  //临时方案矩阵
int result[MAX][MAX];  //最终方案矩阵 
int step = 99999999;  //最小翻转次数
int M,N; 

//cur:当前考虑行  sum:总反转次数 根据第一排灯的情况,后面排的操作 
 void dfs(int cur,int sum){
    if(cur==M){  //试验完一次之后
        int flag = 1;
        for(int i=0;i<N;i++){
            if(cp[M-1][i]==1)  //最后一排还有灯亮着,该方案不可行
                flag = 0; 
        }
        //最后一排所有灯都熄灭了,优化方案 
        if(flag&&sum<=step){
            step = sum;
            for(int i=0;i<M;i++){
                for(int j=0;j<N;j++)
                    result[i][j] = temp[i][j];    
             }
        }
        return;
    }else{
        for(int k=0;k<N;k++){
            if(cp[cur-1][k]==1){
                temp[cur][k]=1;
                sum++;
                
                cp[cur][k] = !cp[cur][k];  //自身翻转
                cp[cur-1][k] = !cp[cur-1][k];  //上一行翻转
                if(cur+1<M) cp[cur+1][k] = !cp[cur+1][k];  //下一行翻转
                if(k-1>=0) cp[cur][k-1] = !cp[cur][k-1];  //左边翻转
                if(k+1<N) cp[cur][k+1] = !cp[cur][k+1];  //右边翻转
                
                
            }else{ 
                temp[cur][k]=0;
            }
        }
        dfs(cur+1,sum);
    }
 }
 
 void op(){
     for(int k=0;k<N;k++){
         if(temp[0][k]==1){
             
             cp[0][k] = !cp[0][k];  //自身翻转 
            if(M>1) cp[1][k] = !cp[1][k];  //下一行翻转
            if(k-1>=0) cp[0][k-1] = !cp[0][k-1];  //左边翻转
            if(k+1<N) cp[0][k+1] = !cp[0][k+1];  //右边翻转
         }
     }
 }
 
 //k:当前考虑的列 sum:第一行总反转次数 
 void todfs(int k, int sum){
     if(k==N){  //已经生成了第一排的序列
         op();//先把第一行的操作执行
         dfs(1,sum);  //从第二行开始
        memcpy(cp,Matri,sizeof(Matri));//试验完之后恢复原矩阵
        return;
     }else{
         temp[0][k] = 1;//翻转
          todfs(k+1,sum+1);
        temp[0][k] = 0;  //不翻转
        todfs(k+1,sum);
     }
 }
int main(int argc, char** argv) {
    while(scanf("%d %d",&M,&N)!=EOF){
        for(int i=0;i<M;i++){
            for(int j=0;j<N;j++){
                scanf("%d",&Matri[i][j]);
            }
        }
        step = 99999999;
        memcpy(cp,Matri,sizeof(Matri));
        memset(temp,0,sizeof(temp)); 
        //对第一排方案进行搜索
        todfs(0,0);
        if(step!=99999999){
             for(int i=0;i<M;i++){
                 for(int j=0;j<N-1;j++)
                     printf("%d ",result[i][j]); 
                cout<<result[i][N-1]<<endl;        
             }
        }else
            cout<<"IMPOSSIBLE"<<endl;
    }
    return 0;
}

 



以上是关于D - Fliptile的主要内容,如果未能解决你的问题,请参考以下文章

D - Fliptile POJ - 3279

Fliptile POJ - 3279(状态压缩)

Enum:Fliptile(POJ 3279)

Fliptile(POJ 3279)

POJ 3279 Fliptile

Poj - 3279 Fliptile