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
  • 92

LightOJ 1057 - Collecting Gold (状压dp)

题意: n∗m(n,m<20)的格子里有最多15个格子有金子,x是出发点,求出发并回来拿完金子的最短路程n*m(n,m<20)的格子里有最多15个格子有金子, x是出发点, 求出发并回来拿完金子的...
  • lwt36
  • lwt36
  • 2015-11-21 04:22
  • 255

lightoj 1037 - Agent 47 状压DP

杀手47游戏背景,有n个目标要杀死,初始手枪一次射击对敌人造成一点伤害,可以用杀死过的敌人的武器杀敌,dps[i][j]是第i个人的武器对第j个人的伤害,问杀完目标需要开多少枪。 范围15,状压DP...

lightoj 1011 Marriage Ceremonies (状压dp)

lightoj 1011 Marriage Ceremonies (状压dp)

lightoj 1018 brush(四)(状压DP)

1018 - Brush (IV) PDF (English) Statistics Forum Time Limit: ...

LightOJ1021---Painful Bases (状压dp)

As you know that sometimes base conversion is a painful task. But still there are interesting facts ...

lightoj 1018 - Brush (IV) 状压DP

有n个点,问可以用几条直线将所有点划去。 n是16,DP分类,很容易想到状压DP。dp[i]代表二进制状态下划去的点的集合下所需要的直线数量。 然后我们考虑的是加新的一条直线的情况下会划去那些点。...

LightOJ 1037 - Agent 47 (状压dp)

题意: 给出n个目标,n<=15,再给出一个n∗n的矩阵,开始他对任何一个目标的伤害是1给出n个目标, n <= 15, 再给出一个n*n的矩阵, 开始他对任何一个目标的伤害是1 等他杀死一...
  • lwt36
  • lwt36
  • 2015-11-13 17:51
  • 323

lightoj1018 - Brush (IV)【状压dp】

1018 - Brush (IV)     PDF (English) Statistics Forum Time Limit: 2 seco...

LightOJ1018状压dp

/***************************************** Author      :Crazy_AC(JamesQi) Time        :2015 File Nam...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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