题目请戳这里
题目大意:给一个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 */