题意:给你一种在3*3矩阵上的开关灯方式,求按哪几个开关能把r*c矩阵上的灯全部点亮
如果直接搜索,2^25再乘上对开关的操作肯定会超时,需要剪枝
剪枝方法:每走到第k行时,判断第k-2行是否全部点亮(第k行的操作不会影响到前k-2行),如果没有全部点亮,cut掉
#include <stdio.h>
#include <string.h>
int map[6][6],n,m,f;
int vis[30];
int ans[30];
int dx[9]={-1,-1,-1,0,0,0,1,1,1};
int dy[9]={-1,0,1,-1,0,1,-1,0,1};
int cn[9];
int dfs(int cur,int p[6][6])
{
if(f)return 0;
if(cur==m*n)
{
int ct=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
if(!p[i][j])ct++;
}
if(ct==0)
{for(int i=0;i<cur;i++)
ans[i]=vis[i];f=1;
}
return 0;
}
int x=cur/m;
int y=cur%m;
if(x>1&&!y)
{
int e=0;
for(int i=0;i<m;i++)
if(!p[x-2][i])e=1;
if(e)return 0;
}
vis[cur]=0;
dfs(cur+1,p);
vis[cur]=1;
int t[6][6];
memcpy(t,p,sizeof(t));
for(int i=0;i<9;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(cn[i])
{
if(xx>=0&&xx<n&&yy>=0&&yy<m)
{
t[xx][yy]=1-t[xx][yy];
}
}
}
dfs(cur+1,t);
return 0;
}
int main()
{
char s[5];int u=0;
while(scanf("%d%d",&n,&m)==2)
{
if(!n&&!m)break;
memset(cn,0,sizeof(cn));
memset(map,0,sizeof(map));
memset(vis,0,sizeof(vis));
memset(ans,0,sizeof(ans));
for(int i=0;i<3;i++)
{
scanf("%s",s);
for(int j=0;j<3;j++)
{
if(s[j]=='*')cn[i*3+j]=1;
}
}
f=0;
dfs(0,map);
printf("Case #%d\n",++u);
int k=0;
if(!f)printf("Impossible.\n");
else
{for(int i=0;i<n*m;i++)
{
if(ans[i])
{
if(k)printf(" ");
printf("%d",i+1);k=1;
}
}
printf("\n");
}
}
return 0;
}