题目中有一个重要提示: 脆弱的房间最多只有15个,而且灯只能放在脆弱的房间(否则一定会照到坚固房间),而且一个房间只能放一个灯,所以枚举所有子集就行了O(2^15)。
一开始没看清题意,以为所有的灯都可以任意朝向,后来才知道只有一个灯可以任意朝向。 所以我们再枚举那个灯是特殊的灯就行了。总复杂度O(15*2^15),可以接受。
细节参见代码:
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
const int INF = 10000000;
const int maxn = 205;
int n,m,maxd,vis[maxn][maxn],cnt;
struct node{
int x,y;
node(int x=0, int y=0) : x(x), y(y) {}
bool operator < (const node& rhs) const {
return x < rhs.x || (x == rhs.x && y < rhs.y);
}
}a[maxn];
char s[maxn][maxn];
map<node,int> p,pp;
int main() {
while(~scanf("%d%d",&n,&m)) {
if(!n && !m) return 0;
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
cnt = 0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(s[i][j] == '.') {
a[cnt++] = node(i,j);
}
}
}
int ans = INF;
if(cnt == 0) { printf("0\n"); continue; }
for(int i=0;i<cnt;i++) {
for(int S=0;S<(1<<cnt);S++) {
if(S & (1<<i)) ; else continue;
int cur = 0, c = 0;
for(int j=0;j<cnt;j++) if(S & (1<<j)) cur++;
bool ok = true;
p.clear(); pp.clear();
for(int j=0;j<cnt;j++) { //放置其他灯
if(i == j) continue;
if(S & (1<<j)) {
node u = a[j];
if(!p.count(u)) { p[u] = 1; c++; }
if(u.x > 1) {
if(s[u.x-1][u.y] == '#') { ok = false; break; }
else {
if(!p.count(node(u.x-1,u.y))) { p[node(u.x-1,u.y)] = 1; c++; }
}
}
if(u.y < m) {
if(s[u.x][u.y+1] == '#') { ok = false; break; }
else {
if(!p.count(node(u.x,u.y+1))) { p[node(u.x,u.y+1)] = 1; c++; }
}
}
}
}
if(!ok) continue; //放置特殊的灯的四种朝向,第一种
node u = a[i];
if(!p.count(u)) { p[u] = 1; c++; }
int cc = c; pp = p;
if(u.x > 1) {
if(s[u.x-1][u.y] == '#') ok = false;
else {
if(!p.count(node(u.x-1,u.y))) { p[node(u.x-1,u.y)] = 1; c++; }
}
}
if(u.y < m) {
if(s[u.x][u.y+1] == '#') ok = false;
else {
if(!p.count(node(u.x,u.y+1))) { p[node(u.x,u.y+1)] = 1; c++; }
}
}
if(ok && c == cnt) ans = min(ans,cur);
/第二种
p = pp; c = cc; ok = true;
if(u.x < n) {
if(s[u.x+1][u.y] == '#') ok = false;
else {
if(!p.count(node(u.x+1,u.y))) { p[node(u.x+1,u.y)] = 1; c++; }
}
}
if(u.y < m) {
if(s[u.x][u.y+1] == '#') ok = false;
else {
if(!p.count(node(u.x,u.y+1))) { p[node(u.x,u.y+1)] = 1; c++; }
}
}
if(ok && c == cnt) ans = min(ans,cur);
第三种
p = pp; c = cc; ok = true;
if(u.x > 1) {
if(s[u.x-1][u.y] == '#') ok = false;
else {
if(!p.count(node(u.x-1,u.y))) { p[node(u.x-1,u.y)] = 1; c++; }
}
}
if(u.y > 1) {
if(s[u.x][u.y-1] == '#') ok = false;
else {
if(!p.count(node(u.x,u.y-1))) { p[node(u.x,u.y-1)] = 1; c++; }
}
}
if(ok && c == cnt) ans = min(ans,cur);
/第四种
p = pp; c = cc; ok = true;
if(u.x < n) {
if(s[u.x+1][u.y] == '#') ok = false;
else {
if(!p.count(node(u.x+1,u.y))) { p[node(u.x+1,u.y)] = 1; c++; }
}
}
if(u.y > 1) {
if(s[u.x][u.y-1] == '#') ok = false;
else {
if(!p.count(node(u.x,u.y-1))) { p[node(u.x,u.y-1)] = 1; c++; }
}
}
if(ok && c == cnt) ans = min(ans,cur);
}
}
if(ans == INF) printf("-1\n");
else printf("%d\n",ans);
}
return 0;
}