题目大意:
R*C的网格上的灯,每操作一次可以改变灯和它周围8个灯的状态,问最少操作几次可以把灯全打开
类似poj3279,枚举第一行第一列,确定之后对每一个灯,如果它左上的灯是关的就必须操作这盏灯,最后检查最后一行最后一列是否为全开
#include <cstdio>
#include <cstring>
int map[10][10];
int flip[10][10];
int mx[]={0,0,0,1,-1,-1,-1,1,1};
int my[]={-1,1,0,0,0,1,-1,1,-1};
int R,C;
//返回灯的状态
int get(int x,int y)
{
int c=map[x][y];
int x1,y1;
for(int i=0;i<9;i++)
{
x1=x+mx[i];
y1=y+my[i];
if(x1>=0&&x1<R&&y1>=0&&y1<C)
{
c+=flip[x1][y1];
}
}
return c % 2;
}
int solve()
{
for(int i=1;i<R;i++)
{
for(int j=1;j<C;j++)
{
//如果左上的一盏为关则必须操作
if(get(i-1,j-1)!=0)
flip[i][j]=1;
}
}
for(int j=0;j<C;j++)
{
if(get(R-1,j)!=0)
return -1;
}
for(int i=0;i<R;i++)
{
if(get(i,C-1)!=0)
return -1;
}
int ans=0;
for(int i=0;i<R;i++)
{
for(int j=0;j<C;j++)
{
ans+=flip[i][j];
}
}
/*
printf(">>>>>>>>>>>>>%d\n",ans);
for(int i=0;i<R;i++)
{
for(int j=0;j<C;j++)
{
printf("%d ",flip[i][j]);
}
printf("\n");
}
*/
return ans;
}
int main()
{
int T,t,ans;
char str[10];
scanf("%d",&T);
for(int iii=1;iii<=T;iii++)
{
scanf("%d%d",&R,&C);
memset(map,0,sizeof(map));
for(int i=0;i<R;i++)
{
scanf("%s",str);
for(int j=0;j<C;j++)
{
if(str[j]=='.')
{
map[i][j]=1;
}
}
}
ans=-1;
//枚举第一行第一列
for(int i=0;i<1<<C;i++)
{
for(int k=0;k<1<<(R-1);k++)
{
memset(flip,0,sizeof(flip));
for(int j=0;j<C;j++)
{
flip[0][C-j-1]=i>>j&1;
}
for(int j=0;j<R-1;j++)
{
flip[R-j-1][0]=k>>j&1;
}
t=solve();
if(t>=0&&(ans<0||ans>t))
ans=t;
}
}
printf("Case %d: ",iii);
if(ans<0)
{
printf("impossible\n");
}
else
{
printf("%d\n",ans);
}
}
return 0;
}