题目链接:
[USACO19JAN]Icy Perimeter S - 洛谷https://www.luogu.com.cn/problem/P5198
思路:
面积很容易求,不解释
对于一个#的连通块,要计算周长,只需要对于每个#,检查它上下左右非#字符的数量(这个数量就是它对周长的“贡献值”,所有“贡献值”加起来,就是周长。
遍历用最简单的dfs即可。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
int n; //边长
const int maxn = 1e3+5;
int s=0, c=0; //面积,周长
int maxS=0, maxC=0; //最大面积和对应的周长
char mp[maxn][maxn]; //记录图形
bool vis[maxn][maxn]; //记录是否遍历过该点
int dx[4] = {1,-1,0,0}, dy[4] = {0,0,1,-1};
void dfs(int x, int y){
if(vis[x][y]||x<1||x>n||y<1||y>n||mp[x][y]=='.') return; //遍历过,或者越界,或者是".",则结束dfs
vis[x][y] = true;
s++; //面积+1
for(int i=0; i<4; i++){
int xi=x+dx[i], yi=y+dy[i];
if(mp[xi][yi] != '#') c++; //如果不是#,说明越界或者和"."邻接,周长+1(因为预留了空间,这里不用担心mp[xi][yi]越界访问)
else dfs(xi, yi);
}
}
int main(){
ios::sync_with_stdio(false);
cin >> n;
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
cin >> mp[i][j];
}
}
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
if(mp[i][j]=='#' && !vis[i][j]){
s=0, c=0; //重置当前的面积和边长
dfs(i,j);
if(s > maxS) {maxS=s; maxC=c;}
else if(s==maxS && c<maxC) maxC=c;
}
}
}
printf("%d %d\n", maxS, maxC);
}