题意:给出一个N*M的图,‘.‘表示需要照亮的格子,'#'表示不能照亮的格子,你现在有一种灯,能照亮 L 形的房间,即某个房间和它上面的以及右边的房间,其中你有且只有一个特殊的灯,能把 L 形旋转一下,问至少几个灯能把'.'全部照亮,不能的话输出-1。
范围:点至多15个,图最大为200*200
解法:首先肯定很容易想到把每个点的状态表示为01串,那么至多为2的15次个状态,这时候进行记忆化搜索,DFS(idx , num , state ,pd) 表示现在正在对第idx个点进行操作,之前已经放了num个灯,已经照亮的格子状态,和判断是否已经放过旋转了的格子,之后直接按题目要求搜索即可,我这里加了一个优化,vis[][][][]数组表示是否已经从这个状态搜索过了,如果搜索过了当然不要再搜了~
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
#include<stdlib.h>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<bitset>
#pragma comment(linker, "/STACK:1024000000,1024000000")
template <class T>
bool scanff(T &ret){ //Faster Input
char c; int sgn; T bit=0.1;
if(c=getchar(),c==EOF) return 0;
while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
sgn=(c=='-')?-1:1;
ret=(c=='-')?0:(c-'0');
while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
if(c==' '||c=='\n'){ ret*=sgn; return 1; }
while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
ret*=sgn;
return 1;
}
#define inf 1073741823
#define llinf 4611686018427387903LL
#define PI acos(-1.0)
#define lth (th<<1)
#define rth (th<<1|1)
#define rep(i,a,b) for(int i=int(a);i<=int(b);i++)
#define drep(i,a,b) for(int i=int(a);i>=int(b);i--)
#define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next)
#define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++)
#define mem(x,val) memset(x,val,sizeof(x))
#define mkp(a,b) make_pair(a,b)
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int n,m;
char s[333][333];
int a[333][333];
struct node{
int x,y;
}b[333];
int an,ans,ed;
int dx[2]={-1,1};
int dy[2]={1,-1};
bool vis[22][22][40000][2];
void dfs(int idx,int num,int state,bool pd){
if(state==ed)ans=min(ans,num);
if(num>=ans)return;
if(idx>an)return;
if(vis[idx][num][state][pd])return;
vis[idx][num][state][pd]=1;
int x=b[idx].x,y=b[idx].y;
int x1,x2,y1,y2,nst=state;
if(pd==0){
x1=x-1;y1=y;
x2=x;y2=y-1;
if(a[x1][y1]!=-1&&a[x2][y2]!=-1){
nst=state|(1<<a[x][y]);
if(s[x1][y1]=='.')nst|=1<<(a[x1][y1]);
if(s[x2][y2]=='.')nst|=1<<(a[x2][y2]);
dfs(idx+1,num+1,nst,1);
}
x1=x+1;y1=y;
x2=x;y2=y-1;
if(a[x1][y1]!=-1&&a[x2][y2]!=-1){
nst=state|(1<<a[x][y]);
if(s[x1][y1]=='.')nst|=1<<(a[x1][y1]);
if(s[x2][y2]=='.')nst|=1<<(a[x2][y2]);
dfs(idx+1,num+1,nst,1);
}
x1=x+1;y1=y;
x2=x;y2=y+1;
if(a[x1][y1]!=-1&&a[x2][y2]!=-1){
nst=state|(1<<a[x][y]);
if(s[x1][y1]=='.')nst|=1<<(a[x1][y1]);
if(s[x2][y2]=='.')nst|=1<<(a[x2][y2]);
dfs(idx+1,num+1,nst,1);
}
}
x1=x-1;y1=y;
x2=x;y2=y+1;
if(a[x1][y1]!=-1&&a[x2][y2]!=-1){
nst=state|(1<<a[x][y]);
if(s[x1][y1]=='.')nst|=1<<(a[x1][y1]);
if(s[x2][y2]=='.')nst|=1<<(a[x2][y2]);
dfs(idx+1,num+1,nst,pd);
}
dfs(idx+1,num,state,pd);
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
if(n==0&&m==0)break;
mem(s,0);
mem(a,0);
rep(i,1,n)scanf("%s",s[i]+1);
an=0;
rep(i,1,n)rep(j,1,m){
if(s[i][j]=='.'){
a[i][j]=an++;
b[an].x=i;
b[an].y=j;
}
else a[i][j]=-1;
}
if(an==0){
printf("0\n");
continue;
}
ed=(1<<an)-1;
rep(i,0,an+1)rep(j,0,an+1)rep(k,0,ed+1)vis[i][j][k][0]=vis[i][j][k][1]=0;
ans=inf;
dfs(1,0,0,0);
if(ans==inf)printf("-1\n");
else printf("%d\n",ans);
}
return 0;
}
/*
3 3
###
#.#
..#
2 2
#.
..
*/

本文介绍了一种解决特定图上L形房间照明问题的方法。通过将问题转化为01串表示的状态空间搜索问题,并利用记忆化搜索进行优化,有效地寻找最少数量的灯来照亮所有目标房间。
216

被折叠的 条评论
为什么被折叠?



