参考http://www.bubuko.com/infodetail-1612583.html和
http://www.cnblogs.com/qscqesze/p/5573329.html
E. Bear and Square Grid (Sliding-window Technique)
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You have a grid with n rows and n columns. Each cell is either empty (denoted by ‘.‘) or blocked (denoted by ‘X‘).
Two empty cells are directly connected if they share a side. Two cells (r1,?c1) (located in the row r1 and column c1) and (r2,?c2) areconnected if there exists a sequence of empty cells that starts with (r1,?c1), finishes with (r2,?c2), and any two consecutive cells in this sequence are directly connected. A connected component is a set of empty cells such that any two cells in the component are connected, and there is no cell in this set that is connected to some cell not in this set.
Your friend Limak is a big grizzly bear. He is able to destroy any obstacles in some range. More precisely, you can choose a square of size k?×?k in the grid and Limak will transform all blocked cells there to empty ones. However, you can ask Limak to help only once.
The chosen square must be completely inside the grid. It‘s possible that Limak won‘t change anything because all cells are empty anyway.
You like big connected components. After Limak helps you, what is the maximum possible size of the biggest connected component in the grid?
Input
The first line of the input contains two integers n and k (1?≤?k?≤?n?≤?500) — the size of the grid and Limak‘s range, respectively.
Each of the next n lines contains a string with n characters, denoting the i-th row of the grid. Each character is ‘.‘ or ‘X‘, denoting an empty cell or a blocked one, respectively.
Output
Print the maximum possible size (the number of cells) of the biggest connected component, after using Limak‘s help.
Examples
input
5 2
..XXX
XX.XX
X.XXX
X…X
XXXX.
output
10
input
5 3
…..
.XXX.
.XXX.
.XXX.
…..
output
25
Note
In the first sample, you can choose a square of size 2?×?2. It‘s optimal to choose a square in the red frame on the left drawing below. Then, you will get a connected component with 10 cells, marked blue in the right drawing.
技术分享
题目大意:有一个n*n的土地,每一点有两种状态,‘X‘表示该点有障碍,‘.‘表示该点为平地,可以将一块k*k大小的土地夷为平地,即将其内的所有‘X‘变成‘.‘,而‘.‘则不变,求如此操作一次后,平地连通块的最大大小为多少?
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN=505;
const int dr[4]={-1,0,1,0};
const int dc[4]={0,1,0,-1};
int n,k,cnt,ans,cur,time;
char g[MAXN][MAXN];
int color[MAXN][MAXN],num[MAXN*MAXN];
int addTime[MAXN*MAXN];
inline bool isInside(int r,int c) {
return 0<=r&&r<n&&0<=c&&c<n;
}
int dfs(int r,int c) {//dfs给同一连通块染色,并返回这一连通块的大小
int rr,cc,sze=1;
for(int i=0;i<4;++i) {
rr=r+dr[i];
cc=c+dc[i];
if(isInside(rr,cc)&&g[rr][cc]=='.'&&color[rr][cc]==0) {
color[rr][cc]=cnt;
sze+=dfs(rr,cc);
}
}
return sze;
}
void getConnectedComponent() {//搜索所有的连通块
memset(color,false,sizeof(color));
cnt=0;
for(int i=0;i<n;++i) {
for(int j=0;j<n;++j) {
if(g[i][j]=='.'&&color[i][j]==0) {
color[i][j]=++cnt;
num[color[i][j]]=dfs(i,j);
}
}
}
}
inline void addConnectedComponent(int r,int c) {//将(r,c)所在的连通块加入答案
if(isInside(r,c)&&g[r][c]=='.'&&addTime[color[r][c]]!=time) {//当(r,c)在范围内且(r,c)为空,且(r,c)所在的连通块本次还未加入答案时,才将其所在的连通块加入答案
addTime[color[r][c]]=time;
cur+=num[color[r][c]];
}
}
int main() {
while(2==scanf("%d%d",&n,&k)) {
for(int i=0;i<n;++i) {
scanf("%s",g[i]);
}
getConnectedComponent();
ans=0;
time=1;
memset(addTime,0,sizeof(addTime));//初始化所有的连通块均未加入答案
for(int r_sta=0;r_sta<=n-k;++r_sta) {//枚举正方形左上角的行坐标
for(int r=r_sta;r<r_sta+k;++r) {//初始化左上角为(r_sta,0)的正方形内连通块的大小
for(int c=0;c<k;++c) {
--num[color[r][c]];
}
}
for(int c_sta=0;c_sta<=n-k;++c_sta) {//枚举正方形左上角的列坐标
cur=k*k;
for(int r=r_sta;r<r_sta+k;++r) {//将正方形外左右两侧的连通块加入
addConnectedComponent(r,c_sta-1);
addConnectedComponent(r,c_sta+k);
}
for(int c=c_sta;c<c_sta+k;++c) {//将正方形外上下两侧的连通块加入
addConnectedComponent(r_sta-1,c);
addConnectedComponent(r_sta+k,c);
}
ans=max(ans,cur);
++time;
if(c_sta!=n-k) {//若正方形还能往右移动
for(int r=r_sta;r<r_sta+k;++r) {
++num[color[r][c_sta]];//正方形内左侧的连通块的大小+1
--num[color[r][c_sta+k]];//正方形外右侧的连通块的大小-1
}
}
}
for(int r=r_sta;r<r_sta+k;++r) {//当前行正方形枚举结束,还原左上角为(r_sta,n-k)的正方形内连通块的大小
for(int c=n-k;c<n;++c) {
++num[color[r][c]];
}
}
}
printf("%d\n",ans);
}
return 0;
}