题目大意:
给出一个地图,要求计算有多少个房间、最大房间的面积、删除哪一面墙会使合并房间的面积最大。
思路:
比较麻烦的搜索题,主要思路是用深搜计算每个房间的面积,时间复杂度属于O(n)级别。
代码:
/* ID: lujunda1 LANG: C++ PROG: castle */ #include<iostream> #include<stdio.h> using namespace std; int n,m,map[51][51],size[51][51],num[51][51]; //map[][]用于存储围墙信息。 //size[i][j]的含义为(i,j)所处房间的大小。 //num[i][j]的含义为(i,j)所处房间的编号。 bool mark[51][51]; //深搜时对访问过的位置进行标记。 bool range(int i,int j) //判断(i,j)是否超界。 { if(i>=1&&i<=n&&j>=1&&j<=m) return true; return false; } int dfs(int i,int j) //深搜,用于计算房间面积。 { if(!range(i,j)||mark[i][j]) //判断是否超界或已访问过。 return 0; mark[i][j]=true; int sum=0; for(int dir=0;dir<4;dir++) if((map[i][j]>>dir)%2==0) //把每个位置上的围墙数据表示成一个4位二进制,可以发现每一位都对应一个方向的墙。 sum+=dfs(i+(dir-2)%2,j+(dir-1)%2); //(i+(dir-2)%2,j+(dir-1)%2)表示与(i,j)一墙之隔的位置的坐标。 return sum+1; } void updata(int i,int j,int val,int order) //由于深搜只能将完整面积返回到房间中第一个被访问的位置上,所以需要通过更新操作更新所有位置的size信息。 //val表示(i,j)所处房间的大小。 //order表示(i,j)所处房间的编号。 { if(!range(i,j)||size[i][j]) return; size[i][j]=val; num[i][j]=order; for(int dir=0;dir<4;dir++) if((map[i][j]>>dir)%2==0) updata(i+(dir-2)%2,j+(dir-1)%2,val,order); } void get_size() //通过updata()和dfs()对size[][]进行赋值。 { int total=0,max=0; //total用于记录方案总数。 //max用于记录房间面积最大值。 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(!mark[i][j]) { updata(i,j,dfs(i,j),++total); max=max>size[i][j]?max:size[i][j]; } printf("%d\n%d\n",total,max); } void remove_wall() //找到题目所要求的墙,并记录新合并的房间的面积。 { int max=0,wall_y,wall_x; //合并房间面积的最大值。 //wall_y、wall_x表示墙所在位置的纵横坐标。 char wall,wall_order[4]={'W','N','E','S'}; //wall存储墙的方向字符。 //关于墙的方向的搜索优先级对应的字符。 for(int j=1;j<=m;j++) for(int i=n;i>=1;i--) //注意题目中要求的搜索优先级,靠西最优先靠南其次。 for(int dir=0;dir<4;dir++) if((map[i][j]>>dir)%2) //若此方向有墙 { int y=i+(dir-2)%2,x=j+(dir-1)%2; if(range(y,x)&&num[i][j]!=num[y][x]) //判断是否超界,两个相邻位置的房间编号是否不同。 { int temp=size[i][j]+size[y][x]; //temp表示两房间的面积和。 if(max<temp) //若max<temp,则更新max和记录该墙的相关信息。 { max=temp; wall_y=i; wall_x=j; wall=wall_order[dir]; } } } printf("%d\n%d %d %c\n",max,wall_y,wall_x,wall); } int main() { freopen("castle.in","r",stdin); freopen("castle.out","w",stdout); scanf("%d%d",&m,&n); //先输入列,再输入行。 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf("%d",&map[i][j]); mark[i][j]=false; size[i][j]=0; } get_size(); remove_wall(); }