题意:N*M的地图,需要照亮所有的'.'(最多15个),但是'#'不能被照亮,问最多需要多少灯。每盏灯能照亮当前格子,右边格子和上方格子。有一盏特别的灯,能够转向。
思路:暴力。枚举所有状态,找出合法且答案最小的状态。状态有三维,第一维是灯的放置情况,第二维是指哪个灯旋转,第三维表示旋转多少度。
#include <stdio.h>
#include <queue>
#include <memory.h>
#include <iostream>
using namespace std;
#define INF 1000000000
char mp[210][210];
int cnt;
bool vis[16];
int nn[16];
int mm[16];
bool judge(int a,int b,int c){
memset(vis,0,sizeof(vis));
int cur=1;
int aa=a;
while(a){
if(a&1){
if(b!=cur){
vis[cur]=1;
char U=mp[nn[cur]-1][mm[cur]];
char R=mp[nn[cur]][mm[cur]+1];
if(U=='#')return 0;
else vis[U]=1;
if(R=='#')return 0;
else vis[R]=1;
}else{
char U,R;
vis[cur]=1;
if(c==1){
U=mp[nn[cur]][mm[cur]+1];
R=mp[nn[cur]+1][mm[cur]];
}else if(c==2){
U=mp[nn[cur]+1][mm[cur]];
R=mp[nn[cur]][mm[cur]-1];
}else if(c==3){
U=mp[nn[cur]][mm[cur]-1];
R=mp[nn[cur]-1][mm[cur]];
}
if(U=='#')return 0;
else vis[U]=1;
if(R=='#')return 0;
else vis[R]=1;
}
}
cur++;
a>>=1;
}
for(int i=1;i<=cnt;i++)if(!vis[i])return 0;
return 1;
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
if(n==0&&m==0)break;
memset(mp,0,sizeof(mp));
cnt=0;
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
for(int j=1;j<=m;j++){
if(mp[i][j]=='.'){
mp[i][j]=++cnt;
nn[cnt]=i; mm[cnt]=j;
}
}
}
if(!cnt){
printf("0\n");
continue;
}
int end=(1<<cnt);
int ans=INF;
for(int i=1;i<end;i++){
for(int j=0;j<=cnt;j++){
for(int k=1;k<=3;k++){
int tmp=i;
int x=0;
while(tmp){
if(tmp&1)x++;
tmp>>=1;
}
if(judge(i,j,k))ans=min(ans,x);
}
}
}
if(ans!=INF)
printf("%d\n",ans);
else
printf("-1\n");
}
return 0;
}