题意:
有矩阵n*m,每个单元是一个房间,有些房间可被照亮有些不能,可被照亮的房间最多15个。在(x,y) 放置灯那么 (x,y+1 )和 (x+1,y)都会被照亮,但是有一盏灯可以转动90或者180或270度。问使得所有可被照亮的房间都被照亮且不可被照亮的房间不被照亮需要的最少的灯,不可能则输出-1.
解法:
可以用状压,枚举哪个房间放灯及灯转动的角度,然后看每个可照亮的房间是否放灯。
代码:
//Time:0ms
//Memory:532KB
//Length:1903B
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 210;
char ma[MAXN][MAXN];
pair<int,int> room[MAXN];
int top=0,ans,bel[MAXN][MAXN];
bool vi[20],tvi[20][20];
int to[4][3][2]={{{0,0},{-1,0},{0,1}},{{0,0},{0,1},{1,0}},{{0,0},{1,0},{0,-1}},{{0,0},{-1,0},{0,-1}}};
inline int cha(int x,int y,int d)
{
int tx,ty,cnt=0,whi;
for(int i=0;i<3;++i)
{
tx=x+to[d][i][0],ty=y+to[d][i][1];
if(ma[tx][ty]=='#') cnt=-MAXN;
if(ma[tx][ty]=='.') whi=bel[tx][ty];
else continue;
cnt+=!vi[whi];
vi[whi]=1;
}
return cnt;
}
void check(int cant,int h,int now,int cnt)
{
int tmp;
if(cnt==top)
{
ans=min(ans,now);
return ;
}
memcpy(tvi[h],vi,sizeof(vi));
for(int i=h;i<top&&now<ans;++i)
if(i!=cant)
{
memcpy(vi,tvi[h],sizeof(vi));
tmp=cha(room[i].first,room[i].second,0);
if(tmp<0) continue;
check(cant,i+1,now+1,cnt+tmp);
}
return ;
}
int main()
{
//freopen("/home/moor/Code/output","r",stdin);
int n,m;
while(scanf("%d%d",&n,&m)==2&&n&&m)
{
memset(ma,0,sizeof(ma));
memset(bel,-1,sizeof(bel));
for(int i=1;i<=n;++i)
scanf("%s",&ma[i][1]);
top=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(ma[i][j]=='.')
bel[i][j]=top,room[top++]=make_pair(i,j);
ans=MAXN;
for(int i=0;i<top;++i)
{
for(int j=0;j<4;++j)
{
memset(vi,0,sizeof(vi));
int tmp=cha(room[i].first,room[i].second,j);
if(tmp<0) continue;
check(i,0,1,tmp);
}
//printf("%d\n",ans);
}
if(top==0) ans=0;
printf("%d\n",ans<MAXN?ans:-1);
}
return 0;
}