zoukankan      html  css  js  c++  java
  • hdu 1882 Strange Billboard(位运算+枚举)

    http://acm.hdu.edu.cn/showproblem.php?pid=1882

    感觉非常不错的一道题。

    给一个n*m(1<=n,m<=16)的矩阵,每一个格子都有黑白两面,当翻一个格子时,它的上下左右都要翻转,问最后使格子全变为白色的最少翻转步数。


    仅仅需枚举第一行的状态即可,由于对于第i(i>=2)行j列翻转情况受上一行的制约,仅仅有当上一行也是‘X’的时候,该行j列才干翻转,使i-1行j列变为‘.’,否则i行j列不能翻转。依次进行下去,当最后一行全变为白色,说明翻转成功。

    一个非常重要的优化:当n < m时,将矩阵转置,这样状态数由 (1<<m)-1 变为 (1<<n)-1。

    跑了280ms,看了其它人的博客,他应该是按行翻转的。只是那一些个位运算,搞不懂。。。


    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <stack>
    #include <vector>
    #include <queue>
    #define LL long long
    #define _LL __int64
    using namespace std;
    const int INF = 0x3f3f3f3f;
    
    int n,m;
    char map[17][17];
    int sta[17],tmp[17];
    int bit[17];
    int ans;
    
    void cal()
    {
    	bit[0] = 1;
    	for(int i = 1; i < 17; i++)
    		bit[i] = (bit[i-1] << 1);
    }
    
    void input()
    {
    	memset(sta,0,sizeof(sta)); //记录每一行的状态
    	if(n >= m)
    	{
    		for(int i = 0; i < n; i++)
    		{
    			scanf("%s",map[i]);
    			for(int j = 0; j < m; j++)
    			{
    				if(map[i][j] == 'X')
    					sta[i] = (sta[i] << 1) + 1;
    				else sta[i] <<= 1;
    			}
    		}
    	}
    	//优化,当m < n时矩阵转换
    	else
    	{
    		for(int i = 0; i < n; i++)
    		{
    			scanf("%s",map[i]);
    			for(int j = 0; j < m; j++)
    			{
    				if(map[i][j] == 'X')
    					sta[j] = (sta[j] << 1) + 1;
    				else sta[j] <<= 1;
    			}
    		}
    		swap(n,m);
    	}
    }
    
    void solve()
    {
    	int step;
    	ans = INF;
    	for(int i = 0; i < (1<<m); i++)
    	{
    		memcpy(tmp,sta,sizeof(sta));
    		step = 0;
    		//先找出第一行应该翻转的列并进行翻转
    		for(int j = 0; j < m && step < ans; j++)
    		{
    			if(bit[j]&i)
    			{
    				step++;
    				if(j > 0)
    					tmp[0] ^= bit[j-1];
    				if(j < m-1)
    					tmp[0] ^= bit[j+1];
    				tmp[0] ^= bit[j];
    				tmp[1] ^= bit[j];
    			}
    		}
    		//依据j-1行的状态依次翻转第j行
    		for(int j = 1; j < n && step < ans; j++)
    		{
    			for(int k = 0; k < m && step < ans; k++)
    			{
    				if(bit[k]&tmp[j-1])
    				{
    					step++;
    					if(k > 0)
    						tmp[j] ^= bit[k-1];
    					if(k < m-1)
    						tmp[j] ^= bit[k+1];
    					tmp[j] ^= bit[k];
    					tmp[j+1] ^= bit[k];
    				}
    			}
    		}
    
    		if(!tmp[n-1])
    			ans = min(ans,step);
    	}
    }
    
    int main()
    {
    	cal();
    	while(~scanf("%d %d",&n,&m))
    	{
    		if(n == 0 && m == 0) break;
    
    		input();
    		solve();
    
    		if(ans == INF)
    			printf("Damaged billboard.
    ");
    		else printf("You have to tap %d tiles.
    ",ans);
    	}
    	return 0;
    }
    


  • 相关阅读:
    Python之CVXOPT模块
    JavaScript之读取和写入cookie
    jQuery学习(2)ajax()使用
    JavaScript之使用AJAX(适合初学者)
    Jquery焦点图实例
    jquery-mobile表单提交问题
    程序员笔记|Spring IoC、面向切面编程、事务管理等Spring基本概念详解
    使用什么调试swoole程序
    swoole模块的编译安装:php编译安装swoole模块的代码
    TP5使用Redis处理电商秒杀
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/3826302.html
Copyright © 2011-2022 走看看