Codeforces Round #356 (Div. 2) Bear and Square Grid
2016-06-10 17:27
513 查看
E. Bear and Square Grid
题意: 给出一个n*n的地图,x表示障碍物。你有一次机会,清除一块k*k区域里的所有障碍物,求最后能得到的最大连通块面积。
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
output
input
output
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.
分析:
直接枚举要清除的区域的左上顶点,依次进行BFS,时间复杂度O(n^4),显然会超时。
注意当窗口移动的时候,其实只有边界在改变,只需要讨论边界的变化即可,时间复杂度降到O(n^3)。
这是一种二维滑动窗口的重要思想。
这道题有很多的细节问题。
预处理:
sum[x][y]: 二维前缀和思想,表示以(1,1) 左上顶点,(x,y)为右下顶点的矩形中,‘.’ 的个数。
每一个连通块的大小size[x]
每一个点所在的连通块编号f[x][y]。
addtime[x][y]表示每一个连通块被“加入”了几次,如果减成了0,就要从当前的答案中减去这一块的大小。
代码如下:
题意: 给出一个n*n的地图,x表示障碍物。你有一次机会,清除一块k*k区域里的所有障碍物,求最后能得到的最大连通块面积。
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.
分析:
直接枚举要清除的区域的左上顶点,依次进行BFS,时间复杂度O(n^4),显然会超时。
注意当窗口移动的时候,其实只有边界在改变,只需要讨论边界的变化即可,时间复杂度降到O(n^3)。
这是一种二维滑动窗口的重要思想。
这道题有很多的细节问题。
预处理:
sum[x][y]: 二维前缀和思想,表示以(1,1) 左上顶点,(x,y)为右下顶点的矩形中,‘.’ 的个数。
每一个连通块的大小size[x]
每一个点所在的连通块编号f[x][y]。
addtime[x][y]表示每一个连通块被“加入”了几次,如果减成了0,就要从当前的答案中减去这一块的大小。
代码如下:
#include<cstdio> #include<iostream> #include<cstdlib> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<algorithm> #define LL long long using namespace std; const int maxn=500+5; char s[maxn][maxn]; int n,k,cnt=0; int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0}; int f[maxn][maxn],sum[maxn][maxn],addtime[maxn*maxn],size[maxn*maxn]; struct node{ int x,y; node(){} node(int x,int y):x(x),y(y){} }; void BFS(int a,int b){ //BFS 求连通块 queue<node> q; q.push(node(a,b)); size[++cnt]=1; f[a][b]=cnt; while(!q.empty()){ node t=q.front(); q.pop(); for(int i=0;i<4;i++){ int tx=t.x+dx[i],ty=t.y+dy[i]; if(tx>0&&tx<=n&&ty>0&&ty<=n&&!f[tx][ty]&&s[tx][ty]=='.'){ q.push(node(tx,ty)); f[tx][ty]=cnt; size[cnt]++; } } } } int Count(int x,int y){ //以(x,y)为左上顶点,k*k的矩形中的点数 return sum[x+k-1][y+k-1]-sum[x+k-1][y-1]-sum[x-1][y+k-1]+sum[x-1][y-1]; } void add(int x,int y,int &cur){ //加点 if(!f[x][y]) return ; int p=f[x][y]; if(!addtime[p])cur+=size[p]; addtime[p]++; } void remove(int x,int y,int & cur){ //删除点 if(!f[x][y]) return ; int p=f[x][y]; addtime[p]--; if(!addtime[p])cur-=size[p]; } int main(){ int i,j,ans=0,x,y; scanf("%d%d",&n,&k); for(i=1;i<=n;i++)scanf("%s",s[i]+1); for(i=1;i<=n;i++) for(j=1;j<=n;j++){ if(!f[i][j]&&s[i][j]=='.')BFS(i,j); sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]; //想一想为什么 if(s[i][j]=='.')sum[i][j]++; } for(i=1;i+k<=n+1;i++){ //左上顶点为(i,?) int cur=0; memset(addtime,0,sizeof(addtime)); for(x=i-1;x<=i+k;x++) for(y=1;y<=k;y++) add(x,y,cur); for(y=i;y<i+k;y++) add(y,k+1,cur); // k*k-COUNT() 是该区域中‘x'的个数 ans=max(ans,cur+k*k-Count(i,1)); for(y=2;y+k-1<=n;y++){ for(x=i;x<i+k;x++){ remove(x,y-2,cur); add(x,y+k,cur); } remove(i-1,y-1,cur); remove(i+k,y-1,cur); add(i-1,y+k-1,cur) ; add(i+k,y+k-1,cur); ans=max(ans,cur+k*k-Count(i,y)); } } printf("%d\n",ans); return 0; }
相关文章推荐
- 343IntegerBreak
- [线性常微分方程][8]The Forced Harmonic Oscillator
- mysql查看表结构
- 【Android】Activity入门
- 1.COM基础概念
- mysql xtrabackup 备份恢复实现,mysql命令备份数据库,打包压缩数据库
- 朱子家训
- Java程序员必须掌握的8大排序算法
- SSL/TLS 协议简介与实例分析
- Eclipse导入git上的maven web项目 部署
- Android View 测量参数
- 数字,日期,时间
- K Reversed Words
- Celery教程-------------以守护进程方式运行worker
- TobHost详解
- BZOJ_2179_FFT快速傅立叶_(FFT)
- 七月算法深度学习笔记6--CNN推展案例:图像检测、NeuralStyle
- A package manager for Qt
- <OJ_Sicily>Prime Palindromes
- Git使用教程