给出n*m的图,图中有不超过200个障碍点,要求把所有连通块的大小从小到大输出。数据保证第一行和最后一行不同时存在障碍,第一列和最后一列不同时存在障碍。
我的做法就是大暴力+map记忆化。对于每一个障碍,找他周围是否存在好的点,如果存在就对这个点做bfs,因为200个障碍点配合边界最大包围的区域为1+2+…+199,所以如果超过这么多个点那么一定不是一个被包围的区间,还有一个优化就是如果行或列与最初的点超过了200,那么这片区间一定不会被障碍点包围。最后一个优化是:每完成一次bfs,都把所有搜到过的点压进去map中,如果下次搜索中还搜到这些点,那么直接退出就行了,因为能搜到的话一定是重复或者不被障碍物包围的。还有一点是,我是先记录一共有多少个好的点,然后每找到一个不重复的连通块,就从最大的那个分出来。
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <set>
#include <vector>
using namespace std;
const int maxn = 202;
struct Node {
int x, y;
bool operator<(const Node &other) const {
if (x < other.x) return true;
if (x > other.x) return false;
if (y < other.y) return true;
return false;
}
}a[maxn];
set<Node> black, certen, seach, found;
vector<Node> q;
int step, max_step, front;
long long ans[maxn], n, m, tot;
bool flag;
Node temp, initial, head;
const int moved[8][2] = {-1,0, 0,-1, 0,1, 1,0, -1,-1, -1,1, 1,-1, 1,1};
bool connect[maxn][maxn];
int main() {
int T;
scanf("%d", &T);
for (int cases = 1; cases <= T; cases++) {
printf("Case #%d:\n", cases);
scanf("%lld%lld", &n, &m);
scanf("%lld", &tot);
black.clear();
for (int i = 1; i <= tot; i++) {
scanf("%d%d", &a[i].x, &a[i].y);
black.insert(a[i]);
}
ans[0] = 1;
ans[1] = n*m-tot;
max_step = max(1ll, tot*(tot-1)/2);
certen.clear();
found.clear();
for (int i = 1; i <= tot; i++) {
for (int k = 0; k < 4; k++) {
initial.x = a[i].x+moved[k][0];
initial.y = a[i].y+moved[k][1];
if (certen.count(initial) || black.count(initial)) continue;
if (initial.x < 1 || initial.x > n || initial.y < 1 || initial.y > m) continue;
q.clear();
seach.clear();
q.push_back(initial);
seach.insert(initial);
flag = true; step = 1; front = 0;
while (front < step) {
head = q[front];
for (int kk = 0; kk < 4; kk++) {
temp.x = head.x+moved[kk][0];
temp.y = head.y+moved[kk][1];
if (black.count(temp) || temp.x < 1 || temp.y < 1 || temp.x > n || temp.y > m) continue;
if (found.count(temp)) {
flag = false; break;
}
if (seach.count(temp)) continue;
step++;
q.push_back(temp);
seach.insert(temp);
if (step > max_step) {
flag = false;
break;
}
if (abs(temp.x-initial.x) > 201 || abs(temp.y-initial.y) > 201) {
flag = false;
break;
}
}
front++;
if (!flag) break;
}
for (int j = 0; j < step; j++) found.insert(q[j]);
if (flag && ans[1] > step) {
for (int j = 0; j < step; j++) certen.insert(q[j]);
ans[1] -= step;
ans[++ans[0]] = step;
}
}
}
sort(ans+1, ans+1+ans[0]);
printf("%lld\n", ans[0]);
printf("%lld", ans[1]);
for (int i = 2; i <= ans[0]; i++) printf(" %lld", ans[i]);
printf("\n");
}
}