LightOJ 1092 Lighted Panels 状压DP

来源:互联网 发布:会计事务所审计软件 编辑:程序博客网 时间:2024/05/01 04:41

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 0x3f3f3f3fusing 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;}



0 0
原创粉丝点击