zoj2977Strange Billboard (状态压缩+枚举)

Strange Billboard


Time Limit: 2 Seconds
Memory Limit: 65536 KB



The marketing and public-relations department of the Czech Technical University has designed a new reconfigurable mechanical Flip-Flop Bill-Board (FFBB). The billboard is a regular two-dimensional grid of
R * C square tiles made of plastic. Each plastic tile is white on one side and black on the other. The idea of the billboard is that you can create various pictures by flipping individual tiles over. Such billboards will hang above all entrances
to the university and will be used to display simple pictures and advertise upcoming academic events.

To change pictures, each billboard is equipped with a "reconfiguration device". The device is just an ordinary long wooden stick that is used to tap the tiles. If you tap a tile, it flips over to the other side, i.e., it changes from white to black or vice
versa. Do you agree this idea is very clever?

Unfortunately, the billboard makers did not realize one thing. The tiles are very close to each other and their sides touch. Whenever a tile is tapped, it takes all neighboring tiles with it and all of them flip over together. Therefore, if you want to change
the color of a tile, all neighboring tiles change their color too. Neighboring tiles are those that touch each other with the whole side. All inner tiles have 4 neighbors, which means 5 tiles are flipped over when tapped. Border tiles have less neighbors,
of course.

For example, if you have the billboard configuration shown in the left picture above and tap the tile marked with the cross, you will get the picture on the right. As you can see, the billboard reconfiguration is not so easy under these conditions. Your
task is to find the fastest way to "clear" the billboard, i.e., to flip all tiles to their white side.

Input

The input consists of several billboard descriptions. Each description begins with a line containing two integer numbers
R and C (1 <= R,C <= 16) specifying the billboard size. Then there are
R lines, each containing C characters. The characters can be either an uppercase letter "X" (black) or a dot "." (white). There is one empty line after each map. The input is terminated by two zeros in place of the board size.

Output

For each billboard, print one line containing the sentence "You have to tap T tiles.", where T is the minimal possible number of taps needed to make all squares white. If the situation cannot be solved, output the string "Damaged billboard." instead.

Sample Input

5 5
XX.XX
X.X.X
.XXX.
X.X.X
XX.XX

5 5
.XX.X
.....
..XXX
..X.X
..X..

1 5
...XX

5 5
...X.
...XX
.XX..
..X..
.....

8 9
..XXXXX..
.X.....X.
X..X.X..X
X.......X
X.X...X.X
X..XXX..X
.X.....X.
..XXXXX..

0 0

Sample Output

You have to tap 5 tiles.
Damaged billboard.
You have to tap 1 tiles.
You have to tap 2 tiles.
You have to tap 25 tiles.

题意:用最少的翻转把所有的X变成点。每翻第(x,y)点同时也会带动周围四个点。
解法:枚举第一行的翻转状态,根据第i-1行翻转第i行。

#include<stdio.h>
#include<iostream>
using namespace std;
#define mulit(j) (1<<j)
#define inf 999999999
int row[18],trow[18],n,m;
int dfs(int i,int prerow,int step)
{
    if(i==n)
    {
        if(prerow)return inf; else return step;
    }
    int now=trow[i],j;
    for(j=0;j<m;j++)
    if(prerow&(1<<j))
    {
        step++;  now^=mulit(j);
        if(j>0)now^=mulit(j-1);
        if(j<m-1)now^=mulit(j+1);
        if(i+1<n)trow[i+1]^=mulit(j);
    }
   return dfs(i+1,now,step);
}
void answer()
{
    int MIN=inf,step;
    for(int i=0;i<(1<<m);i++)
    {
        step=0;
        for(int j=0;j<n;j++)
        trow[j]=row[j];
        for(int j=0;(1<<j)<=i;j++)
        if(i&(1<<j))
        {
            step++; trow[0]^=(1<<j);
            if(j>0)trow[0]^=(1<<(j-1));
            if(j<m-1)trow[0]^=(1<<(j+1));
            if(n>1) trow[1]^=(1<<j);
        }
        step=dfs(1,trow[0],step);
        if(step<MIN)MIN=step;
    }
    if(MIN==inf)printf("Damaged billboard.\n");
    else printf("You have to tap %d tiles.\n",MIN);
}
int main()
{
    char ss[18];
    while(scanf("%d%d",&n,&m)>0&&n+m!=0)
    {
        for(int i=0;i<n;i++)
        {
            scanf("%s",ss);
            row[i]=0;
            for(int j=0;j<m;j++)
            if(ss[j]=='X')
                row[i]|=(1<<j);
        }
       answer();
    }
}

zoj2977Strange Billboard (状态压缩+枚举),布布扣,bubuko.com

时间: 2024-08-01 10:44:03

zoj2977Strange Billboard (状态压缩+枚举)的相关文章

codeforces B - Preparing Olympiad(dfs或者状态压缩枚举)

B. Preparing Olympiad You have n problems. You have estimated the difficulty of the i-th one as integer ci. Now you want to prepare a problemset for a contest, using some of the problems you've made. A problemset for the contest must consist of at le

状态压缩+枚举 POJ 3279 Fliptile

题目传送门 1 /* 2 题意:问最少翻转几次使得棋子都变白,输出翻转的位置 3 状态压缩+枚举:和之前UVA_11464差不多,枚举第一行,可以从上一行的状态知道当前是否必须翻转 4 */ 5 #include <cstdio> 6 #include <cstring> 7 #include <algorithm> 8 using namespace std; 9 10 const int MAXN = 20; 11 const int INF = 0x3f3f3f3

UVA 811 The Fortified Forest (凸包 + 状态压缩枚举)

题目链接:UVA 811 Description Once upon a time, in a faraway land, there lived a king. This king owned a small collection of rare and valuable trees, which had been gathered by his ancestors on their travels. To protect his trees from thieves, the king or

HDU 6607 Time To Get Up(状态压缩+枚举)

题目网址: http://acm.hdu.edu.cn/showproblem.php?pid=6077 思路: 先预处理一下,将每个数字块的"X"看作1,"."看作0,进行状态压缩转换成二进制数,用数组保存.再遍历每个块点的元素,枚举0-9看是否符合当前位数. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 typedef long long l

HDU 5339 Untitled (状态压缩枚举)

Untitled Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 570    Accepted Submission(s): 291 Problem Description There is an integer a and n integers b1,-,bn. After selecting some numbers from b

HDU 4309 Seikimatsu Occult Tonneru(最大流SAP+状态压缩枚举)

Seikimatsu Occult Tonneru Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2012    Accepted Submission(s): 523 Problem Description During the world war, to avoid the upcoming Carpet-bombing fro

SRM 628 DIV2 1000 CandleTimerEasy 状态压缩+DFS

题意:给你一个树型蜡烛,你可以从1个或多个叶子开始点蜡烛,问你能使蜡烛烧完以后能得到时间的个数. 解题思路:状态压缩枚举DFS, 解题代码: 1 // BEGIN CUT HERE 2 /* 3 4 */ 5 // END CUT HERE 6 #line 7 "CandleTimerEasy.cpp" 7 #include <cstdlib> 8 #include <cctype> 9 #include <cstring> 10 #include

hdoj 1074 Doing Homework 【状态压缩dp】

题目:hdoj 1074 Doing Homework 题意:给出一些任务15个,每个任务有截至时间和需要做的天数,超期一天扣一分,求让扣分最小的安排方案. 分析:用状态压缩枚举所有的状态,dp[st]表示在st状态下的最小扣分 转移方程:dp[st | (1<<i)] = min( dp[st | ( 1 << i ) ] , dp[ st ] + 当前 i 超期的扣分 ) 注意这个题目需要打印路径,所以还要一个数组保存状态的转移,递归输出结果即可. AC 代码: #includ

2017盛大游戏杯 零件组装(状态压缩DP之巧妙枚举子集)

题目链接:2017盛大游戏杯 零件组装 题意: 有n个零件,给你相邻关系和排斥关系,每两块零件组装起来有一个代价,问最少的代价总和是多少. 题解: 考虑状态压缩,dp[i]表示i这个集合为一个零件块. 那么要枚举一下i的子集.O(3^n). 先要预处理一下每个集合的排斥个数和相邻个数,然后容斥一下就可以了. 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int