Codeforces325 D【并查集维护连通性】
参考:大牛blog
思路:
因为是环,所以可以复制一下图,先判断一下和他是不是和与他相邻的8个之一的一个障碍使得构成了一个环,环就是一个连通,用并查集维护即可;
如果没有就ans++,然后并把这个点加入。
大致意思就是这样。
#include <cstdio> #include <algorithm> #include <cstring> #include <cstdlib> #include <ctime> #include <cmath> #include <map> #include <set> using namespace std; const int maxn=3000*3000*2+100; const int dx[8]={-1, -1, -1, 0, 0, 1, 1, 1}; const int dy[8]={-1, 0, 1, -1, 1, -1, 0, 1}; int n, r, c, ti; int ans; int fa[maxn]; bool vis[3010][6010]; int mark[maxn]; int find(int cur) { if (fa[cur]<0) return cur; else return (find(fa[cur])); } void Union(int u, int v) { u=find(u); v=find(v); if (u==v) return; if (fa[u]>fa[v]) swap(u, v); fa[u]+=fa[v]; fa[v]=u; } bool check(int &x1, int &y1) { if (x1<1 || x1>r) return false; if (y1==0) y1=c; else if (y1>c) y1=1; if (!vis[x1][y1]) return false; return true; } void merge(int x, int y) { int nid=(x-1)*c+y; for (int i=0; i<8; ++i) { int x1=x+dx[i]; int y1=y+dy[i]; if (check(x1, y1)) Union(nid, (x1-1)*c+y1); } } bool get_list(int x, int y, int id) { for (int i=0; i<8; ++i) { int x1=x+dx[i]; int y1=y+dy[i]; if (!check(x1, y1)) continue; int tmp=find((x1-1)*c+y1); if (id && mark[tmp]==ti-1) return false; mark[tmp]=ti; } return true; } void solve() { if (c==1) return; c*=2; for (int i=1; i<=r; ++i) for (int j=1; j<=c; ++j) fa[(i-1)*c+j]=-1; for (int i=1; i<=n; ++i) { int x, y; scanf("%d%d", &x, &y); ++ti; get_list(x, y, 0); ++ti; bool flag=get_list(x, y+c/2, 1); if (!flag) continue; ++ans; merge(x, y); merge(x, y+c/2); vis[x][y]=true; vis[x][y+c/2]=true; } } int main() { freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); scanf("%d%d%d", &r, &c, &n); solve(); printf("%d\n", ans); return 0; }