E
看上去就很水的题目,然而给的限制是 导致必须使用 vector 存图,于是频繁出锅,卡了我很久。
一开始使用并查集做法,具体思路如下:
使用维护 的并查集,将边界放在同一集合中,将 # 点看做障碍,每个 . 点四方向合并集合,最后统计非边界集合的大小和,加上 # 点数量即为答案。
由于不明原因锅了,改写搜索。
搜索的思路就更加简单了,从每个未访问过的点开始搜索,同时维护当前搜索到的联通块的大小,若遇到边界则打一个标记,代表该联通块大小不计入答案中。复杂度为 。
#include <cstdio> #include <algorithm> #include <vector> #include <ctype.h> const int bufSize = 1e6; using namespace std; inline char nc() { #ifdef DEBUG return getchar(); #endif static char buf[bufSize], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, bufSize, stdin), p1 == p2) ? EOF : *p1++; } inline void read(char *s) { static char c; for (; c != '.' && c != '#'; c = nc()); for (; c == '.' || c == '#'; c = nc()) *s++ = c; *s = '\0'; } template<typename T> inline T read(T &r) { static char c; static int flag; flag = 1, r = 0; for (c = nc(); !isdigit(c); c = nc()) if (c == '-') flag = -1; for (; isdigit(c); c = nc()) r = r * 10 + c - 48; return r *= flag; } const int maxn = 2e6 + 100; vector<char> a[maxn]; char s[maxn]; int n,m,ans,siz,flag; int dx[4] = {1,-1,0,0}; int dy[4] = {0,0,1,-1}; void dfs(int x,int y) { ++siz; a[x][y] = 'a'; for(int i = 0;i<4;++i) { int nx = x + dx[i],ny = y + dy[i]; if(nx < 0 || nx >= n || ny < 0 || ny >= m) {flag = 1;continue;} if(a[nx][ny] == '.') dfs(nx,ny); } } int main() { read(n),read(m); for(int i = 0;i < n;++i) { read(s); for(int j = 0;j < m;++j) a[i].push_back(s[j]); } for(int i = 0;i < n;++i) { for(int j = 0;j<m;++j) { if(a[i][j] == '#') ++ans; else if(a[i][j] == '.') { flag = 0,siz = 0; dfs(i,j); if(!flag) ans += siz; } } } printf("%d\n",ans); return 0; }