LightOJ 1092 Lighted Panels 状压DP

原创 2016年08月28日 22:24:40

Description

You are given an R x C 2D grid consisting of several light panels. Each cell contains either a '*' or a '.''*' means the panel is on, and '.' means it's off. If you touch a panel, its state will be toggled. That means, if you touch a panel that's on, it will turn off, and if you touch a panel that's off, it will turn on. But if we touch a panel, all its horizontal, vertical, and diagonal adjacent panels will also toggle their states.

Now you are given the configuration of the grid. Your goal is to turn on all the lights. Print the minimum number of touches required to achieve this goal.

Input

Input starts with an integer T (≤ 125), denoting the number of test cases.

Each test case starts with two integers R (1 ≤ R ≤ 8) and C (1 ≤ C ≤ 8). Then there will be R lines each containing C characters ('*' or '.').

Output

For each test case, print the case number and the minimum number of touches required to have all the light panels in the board on at the same time. If it is not possible then print "impossible".

Sample Input

4

5 5

*****

*...*

*...*

*...*

*****

1 2

.*

3 3

**.

**.

...

4 4

*...

**..

..**

...*

Sample Output

Case 1: 1

Case 2: impossible

Case 3: 2

Case 4: 10

题意:有一个n*m的矩阵,矩阵中每一行包含两种字符‘.’'*',可以将一个字符相邻的九个格子中的字符全部置为相反的字符,问将矩阵中所有的字符都转化为‘*’所需要的最小转化数

思路:状压DP,由于矩阵的行数和列数都比较小,可以在输入后将每一行转化为10进制数,保存在sta【】中,然后枚举每一行所有的状态以及所有的操作的组合的结果保存在ret【】【】中,ret[i][j]表示当某一行的状态为i时,如果采用j操作去翻转的结果。dp[i][j][k]表示操作完第i行后第i行的状态为j,第i+1行的状态为k时的最小操作数,此时枚举第i+1行的操作,选取其中能让此时第i行由状态j变为全0的操作,更新最小操作数,最后枚举最后一行的操作,如果不存在一个操作能使最后一行和倒数第二行同时为全0,则输出误解,否则输出结果。

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <cmath>
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
int dp[10][260][260],ret[300][300],sta[10],opt[300];
char str[20];
int cal(int opt,int sat){
    int res=sat,tmp=opt;
    int ii=0;
    while(tmp){
        if(tmp&1){
            if(ii>0) res^=(1<<(ii-1));
            res^=(1<<ii);
            if(ii<m-1) res^=(1<<(ii+1));
        }
        tmp=tmp>>1;
        ii++;
    }
    //cout<<sat<<' '<<opt<<' '<<res<<endl;
    return res;
}
int cnt_opt(int op){
    int tmp=op;
    int res=0;
    while(tmp){
        if(tmp&1) res++;
        tmp=tmp>>1;
    }
    return res;
}
void init(){
    for(int i=0;i<n;++i)
        for(int j=0;j<(1<<m);++j)
            for(int k=0;k<(1<<m);++k)
                dp[i][j][k]=INF;
    memset(sta,0,sizeof(sta));
    for(int i=0;i<(1<<m);++i){
        opt[i]=cnt_opt(i);
        for(int j=0;j<(1<<m);++j){
            ret[j][i]=cal(i,j);
        }
    }
}
int main()
{

    int T,cas=1;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        init();
        for(int i=0;i<n;++i){
            scanf("%s",str);
            for(int j=m-1;j>=0;--j)
                if(str[j]=='.') sta[i]+=(1<<(m-1-j));
            //cout<<sta[i]<<endl;
        }
        int ans=INF;
        if(n==1){
            for(int i=0;i<(1<<m);++i){
                if(ret[sta[0]][i]==0) ans=min(ans,opt[i]);
            }
            if(ans==INF) printf("Case %d: impossible\n",cas++);
            else printf("Case %d: %d\n",cas++,ans);
            continue;
        }
        dp[0][sta[0]][sta[1]]=0;
        for(int i=0;i<(1<<m);++i){
            dp[0][ret[sta[0]][i]][ret[sta[1]][i]]=min(dp[0][ret[sta[0]][i]][ret[sta[1]][i]],opt[i]);
        }
        for(int i=0;i<n-2;++i)
            for(int j=0;j<(1<<m);++j)
            for(int k=0;k<(1<<m);++k)
                if(dp[i][j][k]!=INF){
                    for(int op=0;op<(1<<m);++op){
                    if(ret[j][op]==0){
                        //cout<<j<<' '<<k<<' '<<op<<endl;
                        dp[i+1][ret[k][op]][ret[sta[i+2]][op]]=min(dp[i+1][ret[k][op]][ret[sta[i+2]][op]],dp[i][j][k]+opt[op]);
                    }
                }
                //cout<<dp[1][sta[1]][sta[2]]<<endl;
                }
        for(int i=0;i<(1<<m);++i)
            for(int j=0;j<(1<<m);++j)
                for(int k=0;k<(1<<m);++k){
                     if(ret[i][k]==0&&ret[j][k]==0){
                        ans=min(ans,dp[n-2][i][j]+opt[k]);
                     }
                }
        if(ans==INF) printf("Case %d: impossible\n",cas++);
        else printf("Case %d: %d\n",cas++,ans);
    }
    return 0;
}



版权声明:本文为博主原创文章,未经博主允许不得转载。

Light OJ 1092 Lighted Panels (状压DP)

1092 - Lighted Panels     PDF (English) Statistics Forum Time Limit: 3 second(s) Memory ...
  • jncsw
  • jncsw
  • 2016年07月13日 14:28
  • 156

LightOJ 1092 Lighted Panels(状压+高斯消元)

Lighted Panels Time Limit: 3000MS Memory Limit: 32768KB 64bit IO Format: %lld & %llu Su...
  • mrlry
  • mrlry
  • 2016年08月15日 19:26
  • 252

[状压dp] lightoj 1092 Lighted Panels

状态压缩dp
  • gdymind
  • gdymind
  • 2016年07月13日 12:58
  • 449

Light OJ 1092 Lighted Panels (状压)

解析:可以参考POJ 3279。不同的是这里要把最上面一行和最左一行一起状压。 [code]: #include #include #include using namespace std; c...
  • qq_26572969
  • qq_26572969
  • 2016年03月25日 11:52
  • 244

对状压dp的一点理解

博主是初学者,一下紧代表个人观点,若有错误欢迎指出。 状压dp       此dp可以理解为最暴力的dp,因为他需要遍历每个状态,所以将会出现2^n的情况数量,所以明显的标志就是数据不能太多(好像是 ...
  • benTuTuT
  • benTuTuT
  • 2017年04月12日 21:51
  • 851

状压DP 入门题

一:方格取数 问题描述: Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数。 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不...
  • sinat_34336698
  • sinat_34336698
  • 2016年08月06日 16:33
  • 1619

状压DP问题

状态压缩·一题目传送:#1044 : 状态压缩·一AC代码:#include #include #include #include #include #include #include ...
  • u014355480
  • u014355480
  • 2015年08月17日 15:00
  • 878

状压DP小结

状压dp其实就是将状态压缩成2进制来保存 其特征就是看起来有点像搜索,每个格子的状态只有1或0 模板题,poj3254 就是先给一个map,在这个有些地方不能放牛,有些地方可以 然后牛与牛之间...
  • cbcbcbz
  • cbcbcbz
  • 2017年07月23日 10:40
  • 180

状压DP入门题集锦

POJ 3254 Corn Fields 题意: 一块n*m的田,1表示这个地方可以种植,0代表这个地方不能种植。植物种植还必须满足两株植物不能相邻(横竖都不行)。问共有几种种植方法,而且当...
  • Codeblocksm
  • Codeblocksm
  • 2016年03月05日 10:52
  • 404

【总结】状压DP

状压DP还是比较恶心的。std代码看不懂,默默把DP全打成记忆搜(…………),位运算虽然知道,但看见代码里充斥着一堆 > & ^ | ~ 感觉心很痛。。。。。 只要理解了倒还是能打。(代码风格变了强...
  • qq_21436421
  • qq_21436421
  • 2017年02月18日 21:30
  • 288
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:LightOJ 1092 Lighted Panels 状压DP
举报原因:
原因补充:

(最多只允许输入30个字)