欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ4997
题意概括
在n*n的区域里,每一个1*1的块都是一个格子。
有k头牛在里面。
有r个篱笆把格子分开。
如果两头牛可以不经过篱笆走到一起(过程中不能出界),那么他们就是不互相远离的,反之就是互相远离的。
问有多少对牛是互相远离的。注意(x,y)和(y,x)算作同样的。
题解
对于同一区域的牛,我们可以相同对待。
所以我们dfs给各自连通的区域分开来,分别统计每一块的牛数,然后乘法原理+加法原理就可以了。
代码
#include <cstring> #include <cstdio> #include <algorithm> #include <cstdlib> #include <cmath> using namespace std; const int N=100+5; const int dx[4]={ 0, 0,-1, 1}; const int dy[4]={-1, 1, 0, 0}; int n,m,k,r,v[N][N],cnt,tot[N*N]; bool f[N][N][4]; int find_d(int x,int y){ for (int i=0;i<4;i++) if (x==dx[i]&&y==dy[i]) return i; return -1; } void dfs(int x,int y){ if (v[x][y]) return; v[x][y]=cnt; for (int i=0;i<4;i++) if (!f[x][y][i]) dfs(x+dx[i],y+dy[i]); } int main(){ scanf("%d%d%d",&n,&k,&r); memset(f,0,sizeof f); for (int i=1;i<=n;i++){ f[i][1][0]=1; f[i][n][1]=1; f[1][i][2]=1; f[n][i][3]=1; } cnt=0; for (int i=1;i<=r;i++){ int x_1,y_1,x_2,y_2,x,y; scanf("%d%d%d%d",&x_1,&y_1,&x_2,&y_2); x=x_2-x_1,y=y_2-y_1; f[x_1][y_1][find_d(x,y)]=1; f[x_2][y_2][find_d(-x,-y)]=1; } cnt=0; memset(v,0,sizeof v); memset(tot,0,sizeof tot); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) if (!v[i][j]){ cnt++; dfs(i,j); } for (int i=1,x,y;i<=k;i++){ scanf("%d%d",&x,&y); tot[v[x][y]]++; } m=cnt; int sum=0,ans=0; for (int i=1;i<=m;i++) sum+=tot[i]; for (int i=1;i<=m;i++){ sum-=tot[i]; ans+=tot[i]*sum; } printf("%d",ans); return 0; }