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 Output for Sample Input 
4

5 5

*****

*...*

*...*

*...*

*****

1 2

.*

3 3

**.

**.

...

4 4

*.
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
#define inf 1<<29
int r,c;
char g[10];
int maz[10],res,rnk[2][1<<8][1<<8];
struct node{
    int a,b;
    int r;
    node(){};
    node(int _a,int _b,int _r){
        a=_a,b=_b,r=_r;
    };
};

void input(){
    scanf("%d%d",&r,&c);
    memset(maz,0,sizeof(maz));
    for(int i=1;i<=r;i++){
        scanf("%s",g);
        for(int j=0;j<c;j++) if(g[j]=='*') maz[i]+=(1<<j);
    }
}

int cal(int x){
    int s=(1<<x);
    if(x>0) s^=(1<<(x-1));
    if(x+1<c) s^=(1<<(x+1));
    return s;
}

void bfs(){
    res=inf;
    for(int i=0;i<(1<<c);i++) for(int j=0;j<(1<<c);j++) rnk[0][i][j]=inf;
    queue<node>q;
    for(int i=0;i<(1<<c);i++){
        q.push(node(i,maz[1],1));
        rnk[0][i][maz[1]]=0;
    }
    int rt=0;
    while(!q.empty()){
        node pnt=q.front();
        q.pop();
        int a=pnt.a,b=pnt.b,rc=pnt.r;
//        printf("%d %d %d\n",a,b,rc);
//        getchar();
        if(rc==r+1){
            for(int i=0;i<(1<<c);i++){
                res=min(res,rnk[r%2][(1<<c)-1][i]);
//                printf("%d %d\n",i,rnk[r%2][(1<<c)-1][i]);
            }
            return;
        }
        if(rc!=rt){
            rt=rc;
            for(int i=0;i<(1<<c);i++) for(int j=0;j<(1<<c);j++) rnk[rc%2][i][j]=inf;
        }
        for(int i=0;i<(1<<c);i++){
            int s=0,num=0;
            for(int j=0;j<c;j++) if(i&(1<<j)) num++,s^=cal(j);
//            printf("%d    %d    %d\n",i,s,num);
//            getchar();
            int t=a^s;
            if(t!=(1<<c)-1) continue;
            int ta=b^s,tb=maz[rc+1]^s;
            if(rnk[rc%2][ta][tb]>rnk[(rc+1)%2][a][b]+num){
                if(rnk[rc%2][ta][tb]==inf) q.push(node(ta,tb,rc+1));
                rnk[rc%2][ta][tb]=rnk[(rc+1)%2][a][b]+num;
            }
        }
    }
    return;
}

int main(){
    int t,cas=1;
    cin>>t;
    while(t--){
        input();
        bfs();
        printf("Case %d: ",cas++);
        if(res==inf) puts("impossible");
        else printf("%d\n",res);
    }
    return 0;
}

  

 

做这题之前,可以先去看看POJ的一条经典动态规划,名字叫炮兵阵地,题型很相似。

根据题意,dp[i][j][k]表示第i行时,状态为j,第i-1行的状态是k,的最小步数。

关于动态规划的递推,有几种方法,一种是使用DFS深搜回溯,还有就是直接有几维就几个for。

这题我用了bfs来优化for递推,这样快一点,避免了没必要的运算。

posted on 2013-04-14 01:42  SCAU_Xxm  阅读(467)  评论(0)    收藏  举报