zoukankan      html  css  js  c++  java
  • POJ 3279 Fliptile(枚举)

    题目链接

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

    题意

    给定M*N的瓦片矩阵,瓦片正反为不同的颜色:1(黑色),0(白色)。当触摸一个瓦片时,这块瓦片和其上下左右的瓦片都会翻动(即黑色变为白色,白色变为黑色)。问是否有一种触摸方法使所有瓦片都是白色面朝上。若存在则输出翻动次数最少的方法,若不能输出"IMPOSSIBLE"

    思路

    1. 首先要明白,触摸同一个瓦片两次相当于没有触摸这块瓦片,所以对于任意一块瓦片,触摸的次数不是0就是1(触摸的次数,不是翻动的次数)
    2. 解题方法是枚举,但并不是枚举每个瓦片触摸的次数,只枚举第一行的即可,当确定第一行瓦片触摸的次数后,2m行瓦片触摸的次数是确定的。对于2m行的任意一个瓦片(x, y),若瓦片(x-1,y)是黑色的,那么就触摸一次改瓦片(x,y),这样瓦片(x-1,y)就变成了白色,同理通过控制是否触摸(x+1, y)来确保瓦片(x,y)的颜色是白色。这样,最后查看最后一行是否全部为白色即可确定这种触摸方法是否可行。
    3. 枚举第一行瓦片触摸次数的方法是用二进制0,1表示相应位数上瓦片的触摸次数

    代码

    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    
    using namespace std;
    
    const int INF = 0x3f3f3f3f;
    
    int tile[16][16];//输入的瓦片矩阵
    int time[16][16];//枚举的时候用到的,保存每块瓦片触摸的次数
    int tmp[16][16];//也是枚举的时候用到的,保存触摸后瓦片朝上的颜色
    int final_ans[16][16];//保存最优解
    int m, n;
    int ans, cur;
    //顺序:左,当前,右,上
    int dx[] = {0, 0, 0, -1};
    int dy[] = {-1, 0, 1, 0};
    
    bool judge(int x, int y){
    	return x >= 0 && x < m && y >= 0 && y < n;
    }
    
    int solve(){
    	memcpy(tmp, tile, sizeof tile);
    	//执行第一行进行的翻转
    	int x = 0, tx, ty;
    	for (int y = 0; y < n; ++y){   //瓦片(0, y)
    		for (int i = 0; i < 4; ++i){
    			tx = x + dx[i];
    			ty = y + dy[i];
    			if (judge(tx, ty)){
    				tmp[x][y] += time[tx][ty];
    			}
    		}
    		tmp[x][y] %= 2;
    	}
    	//从第二行开始,将上一行所有瓦片变为白色
    	for (x = 1; x < m; ++x){
    		//若(x-1,y)是黑色,翻转(x,y)
    		for (int y = 0; y < n; ++y){
    			time[x][y] = tmp[x - 1][y];
    		}
    		//执行翻转
    		for (int y = 0; y < n; ++y){
    			for (int i = 0; i < 4; ++i){
    				tx = x + dx[i];
    				ty = y + dy[i];
    				if (judge(tx, ty)){
    					tmp[x][y] += time[tx][ty];
    				}
    			}
    			tmp[x][y] %= 2;
    		}
    	}
    	//检查最后一行瓦片是否全部为白色
    	x = m - 1;
    	for (int y = 0; y < n; ++y){
    		if (tmp[x][y]){
    			return -1;
    		}
    	}
            //统计翻动的次数
    	int s = 0;
    	for (int i = 0; i < m; ++i){
    		for (int j = 0; j < n; ++j){
    			s += time[i][j];
    		}
    	}
    	return s;
    }
    
    int main(){
    	while (~scanf("%d%d", &m, &n)){
    		//读入数据
    		for (int i = 0; i < m; ++i){
    			for (int j = 0; j < n; ++j){
    				scanf("%d", &tile[i][j]);
    			}
    		}
    		ans = INF;
    		//枚举第一行瓦片翻转的次数
    		int ed = 1 << n;
    		for (int i = 0; i < ed; ++i){
    			memset(time, 0, sizeof time);
    			for (int j = 0; j < n; ++j){
    				if (i & (1 << j)){
    					time[0][n - j - 1] = 1;
    				}
    			}
    			cur = solve();
    			if (cur >= 0 && cur < ans){
    				ans = cur;
    				memcpy(final_ans, time, sizeof time);
    			}
    		}
    		if (ans == INF){
    		   printf("IMPOSSIBLE
    ");
    		}
    		else{
    			for (int j = 0; j < m; ++j){
    				for (int k = 0; k < n; ++k){
    					printf("%d ", final_ans[j][k]);
    				}
    				printf("
    ");
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    [译]Node.js Interview Questions and Answers (2017 Edition)
    XUnit
    Inline Route Constraints in ASP.NET Core MVC
    [译]Object.getPrototypeOf
    [译]IIS 8.0应用初始化
    C++的那些事:你真的了解引用吗
    C++的那些事:表达式与语句
    C++的那些事:数据与类型
    神经网络:卷积神经网络
    图像分析:投影曲线的波峰查找
  • 原文地址:https://www.cnblogs.com/lucianosimon/p/7401123.html
Copyright © 2011-2022 走看看