HDU 1882 Strange Billboard(状态压缩+转置优化)

  状态压缩,我们枚举第一行的所有状态,然后根据第一行去转变下面的行,枚举或者深搜直到最后最后一行,可以判断是不是所有的1都可以全部转换为0,记录所有的解,输出最小的一个就可以.

这里有一个很重要的优化,就是当n比m大的,转置这个矩阵,如果不加这个在G++的情况下会超时,C++900Ms多AC.代码及注释如下

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f
int row[20],newrow[20],n,m;
int dfs(int id,int prerow,int tot)
{
    if(id == n)
    {
        if(prerow != 0)return inf;
        else return tot;
    }
    int now = newrow[id];///这是当前行
    for(int j = 0; j < m; j++)
        if(prerow & (1<<j))///now(当前行)受prerow(前一行)的限制,只有prenow的这一列也是X的时候才可以反转
        {
            tot++;
            now ^= 1<<j;
            if(j > 0)now ^= 1<<(j-1);
            if(j < m-1)now ^= 1<<(j+1);
            if(id+1 < n)newrow[id+1] ^= 1<<(j);///当前行的下一行
        }
    dfs(id+1,now,tot);
}
int main()
{
    char maps[20][20];
    while(~scanf("%d%d",&n,&m))
    {
        if(n == 0 && m == 0) return 0;
        for(int i = 0; i < n; i++)
            scanf("%s",maps[i]);
        if(n >= m)
        {
            for(int i = 0; i < n; i++)
            {
                row[i] = 0;
                for(int j = 0; j < m; j++)
                    if(maps[i][j] == 'X')
                        row[i] |= (1<<j);
            }
        }
        else///转置优化
        {
            for(int i = 0; i < m; i++)
            {
                row[i] = 0;
                for(int j = 0; j < n; j++)
                    if(maps[j][i] == 'X')
                        row[i] |= (1<<j);
            }
            swap(n,m);
        }
        int ans = inf,tot;
        for(int i=0; i<(1<<m); i++)///枚举第一行的所有状态
        {
            tot = 0;
            for(int j = 0; j < n; j++)
                newrow[j] = row[j];
            for(int j=0; (1<<j)<=i; j++)
                if(i & (1<<j))///如果是X就反转,并且带动周围4个点,边界需要特判
                {
                    tot++;
                    newrow[0] ^= (1<<j);
                    if(j > 0)newrow[0] ^= (1<<(j-1));
                    if(j < m-1)newrow[0] ^= (1<<(j+1));
                    if(n > 1) newrow[1] ^= (1<<j);
                }
            tot = dfs(1,newrow[0],tot);///开始搜索到最后一行
            if(tot < ans)ans = tot;
        }
        if(ans == inf)printf("Damaged billboard.
");
        else printf("You have to tap %d tiles.
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jifahu/p/5452657.html