题目大意:给一个n*m的格子,每个格子可以是'#'或者是'.'。'.'的数量不超过15个。现在要在'.'的位置放一种灯,假设放在(x,y)的位置。那么这盏灯只能点亮(x,y),(x-1,y),(x,y + 1),这3个位置。现在有一盏灯比较特殊,可以绕(x,y)旋转0度,90度,180度或者270度。现在给这样n*m的格局,求最少放置多少灯能覆盖所有的'.'。每个'.'的位置只能放置一盏灯,但是'.'的位置可以重复照射。'#'的位置不能被照射。
题目分析:第一反应是重复覆盖问题。不过今天不在状态,一开始想复杂了。
一共有15盏灯,每盏灯有4个姿势,那么一共就是15*4行,一共要覆盖15盏灯,那么就是15列。
枚举每个点的4个姿势,建图。然后再枚举那盏能旋转的灯。然后直接跑DLX重复覆盖即可。
详情请见代码:
#include <iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N = 201;
const int M = 910;
char map[N][N];
int vnum,n,m,num,cur;
short int s[M],h[M],u[M],d[M],l[M],r[M],col[M],row[M];
bool flag[N];
int dir[4][2] = {-1,0,0,1,1,0,0,-1};
int pt[N][2];
int ans,sp;
void init()
{
memset(h,0,sizeof(h));
memset(s,0,sizeof(s));
for(int i = 0;i <= vnum;i ++)
{
u[i] = d[i] = i;
l[i] = (i + vnum)%(vnum + 1);
r[i] = (i + 1)%(vnum + 1);
}
num = vnum + 1;
}
void add(int i,int j)
{
if(h[i])
{
r[num] = h[i];
l[num] = l[h[i]];
r[l[num]] = l[r[num]] = num;
}
else
h[i] = l[num] = r[num] = num;
s[j] ++;
u[num] = u[j];
d[num] = j;
d[u[num]] = num;
u[j] = num;
col[num] = j;
row[num] = i;
num ++;
}
void remove(int c)
{
for(int i = d[c];i != c;i = d[i])
{
l[r[i]] = l[i];
r[l[i]] = r[i];
s[col[i]] --;
}
}
void resume(int c)
{
for(int i = u[c];i != c;i = u[i])
l[r[i]] = r[l[i]] = i,s[col[i]] ++;
}
void build()
{
int i,j;
for(i = 0;i < vnum;i ++)
{
for(j = 0;j < 4;j ++)
{
int tx = pt[i][0] + dir[j][0];
int ty = pt[i][1] + dir[j][1];
int ttx = pt[i][0] + dir[(j + 1)%4][0];
int tty = pt[i][1] + dir[(j + 1)%4][1];
int x = pt[i][0];
int y = pt[i][1];
if(map[tx][ty] == '#' || map[ttx][tty] == '#')
continue;
if(tx >= 1 && tx <= n && ty >= 1 && ty <= m)
add(i * 4 + j,map[tx][ty]);
if(ttx >= 1 && ttx <= n && tty >= 1 && tty <= m)
add(i * 4 + j,map[ttx][tty]);
add(i * 4 + j,map[x][y]);
}
}
}
void dfs(int k)
{
if(!r[0])
{
cur = min(cur,k);
return;
}
int i,j,c,mn = N;
for(i = r[0];i;i = r[i])
{
if(s[i] < mn)
{
mn = s[i];
c = i;
}
}
for(i = d[c];i != c;i = d[i])
{
if(flag[row[i]/4] == true)
continue;
if(row[i]%4 && row[i]/4 != sp)
continue;
remove(i);
flag[row[i]/4] = true;
for(j = r[i];j != i;j = r[j])
remove(j);
dfs(k + 1);
for(j = l[i];j != i;j = l[j])
resume(j);
flag[row[i]/4] = false;
resume(i);
}
}
void dance()
{
ans = M;
int i;
for(i = 0;i < vnum;i ++)
{
sp = i;
cur = M;
memset(flag,false,sizeof(flag));
dfs(0);
ans = min(ans,cur);
}
if(ans == M)
ans = -1;
printf("%d\n",ans);
}
int main()
{
int i,j;
char ss[300];
while(scanf("%d%d",&n,&m),(n + m))
{
vnum = 0;
gets(ss);
memset(map,0,sizeof(map));
for(i = 1;i <= n;i ++)
{
for(j = 1;j <= m;j ++)
{
map[i][j] = getchar();
if(map[i][j] == '.')
{
pt[vnum][0] = i;
pt[vnum][1] = j;
vnum ++;
map[i][j] = vnum;
}
}
getchar();
}
if(vnum == 0)
{
printf("0\n");
continue;
}
init();
build();
dance();
}
return 0;
}
//0MS 296K
/*
2 3
#..
..#
3 3
###
#.#
###
4 4
#...
....
....
....
3 3
#.#
...
#.#
4 4
####
#..#
#..#
####
4 7
#######
##.#.##
#..#..#
#######
2 2
#.
##
3 3
#.#
...
..#
0 0
*/