题目
原题链接:https://www.nowcoder.com/acm/contest/106/L
在100000 * 10000的空地上,有n个时间点,每个时间点会在(xi,yi)上种一棵树。
定义绿色:被树包围的空地的个数。
问每个时间点之后绿色为多少。如图:
思路
逆向求解,从(0,0)位置将圈外的全标记(给空地加一圈),在分别考虑当前的树,是在圈内还是圈的外围。
由于vis是全局数组,之后的bfs都非常快,每个点只遍历过一次。
代码实现
1 #include<stdio.h> 2 #include<queue> 3 #include<iostream> 4 using namespace std; 5 6 typedef pair<int, int> P; 7 const int maxn = 100000 + 10; //点的最大个数 8 const int SIZE = 2000 + 10; //地图大小 9 const int offset = 1000; //偏置 10 const int dx[] = { -1,0,1,0 }; 11 const int dy[] = { 0,1,0,-1 }; 12 int n,xi[maxn],yi[maxn],ans[maxn]; 13 bool vis[SIZE][SIZE], maze[SIZE][SIZE]; 14 15 int bfs(int x, int y) 16 { 17 int ret = 0; 18 queue<P>q; 19 vis[x][y] = true; 20 q.push(P(x, y)); 21 while (!q.empty()) 22 { 23 P p = q.front(); q.pop(); 24 ret++; 25 for (int i = 0; i < 4; i++) 26 { 27 int nx = p.first + dx[i], ny = p.second + dy[i]; 28 if (nx >= 0 && nx < SIZE && ny >= 0 && ny < SIZE && (!vis[nx][ny])) 29 { 30 vis[nx][ny] = true; 31 q.push(P(nx, ny)); 32 } 33 } 34 } 35 return ret; 36 } 37 38 int main() 39 { 40 scanf("%d", &n); 41 for(int i = 1;i <= n;i++) 42 { 43 scanf("%d%d", &xi[i], &yi[i]); 44 maze[xi[i] + offset][yi[i] + offset] = 1; 45 vis[xi[i] + offset][yi[i] + offset] = 1; 46 } 47 48 bfs(0, 0); 49 int res = 0; 50 for (int i = 0; i < SIZE; i++) 51 for (int j = 0; j < SIZE; j++) 52 if (vis[i][j] == false) res++; 53 ans[n] = res; 54 55 for (int i = n; i >= 4; i--) //1~3棵以内不可能围成空地 56 { 57 int u = xi[i] + offset; 58 int v = yi[i] + offset; 59 maze[u][v] = 0; 60 int cnt = 0; 61 for (int j = 0; j < 4; j++) 62 { 63 int nu = u + dx[j], nv = v + dy[j]; 64 if (maze[nu][nv] == 0 && vis[nu][nv] == 1) cnt++; 65 } 66 if (cnt == 0) //cnt == 0,表示该点在内部 67 { 68 vis[u][v] = 0; 69 res++; 70 } 71 else res -= (bfs(u, v) - 1); 72 ans[i - 1] = res; 73 } 74 for (int i = 1; i <= n; i++) 75 printf("%d ", ans[i]); 76 return 0; 77 }
参考链接:https://www.nowcoder.com/acm/contest/view-submission?submissionId=26038731