zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Oracle between and 边界问题
    多线程——什么是并发与并行
    js:浅拷贝和深拷贝
    JavaScript中数组元素删除的七大方法汇总
    js 去掉字符串前面的0
    chrome总是提示"喔唷,崩溃啦"的解决办法
    智慧城市管理信息系统建设项目的架构分析
    利用DenseUNet深度神经网络数之联河湖遥感大数据的研究
    无人机+数字孪生助力河长制巡查方法探讨
    防汛可视化指挥平台“一张图”技术研究
  • 原文地址:https://www.cnblogs.com/jifahu/p/5452657.html
Copyright © 2011-2022 走看看