题意:给出二维平面的n个点坐标,定义一种操作:若恰好三个点能形成一个矩形(当然这个矩形会缺了一个点),那么就在图上添加这个缺的点,问在原图上最多能进行几次这样的操作。
解法:这题想了挺久没想到,一看题解发现z自己思路和正解完全不沾边(尴尬)。解法参考https://www.cnblogs.com/zaq19970105/p/11108175.html这位大佬的。我们把x轴看作二分图的左边点,y轴看作二分图右边点,对于原图上的点就向左边点向右边点连边,即二分图一条边就是原图一个点。然后我们先观察四个点能构成矩形有什么特点:如果在二分图上左边任意两个点和任意右边两个点有4条连边就是能构成矩形,那么怎么才是缺一个点呢?基于上面就不难想了,就是左两个点和右两个点只有3条边,那么缺的那一条边就是缺的点。然后接下来这个发现就难一点了,就是如果左两个点右两个点至少有3条边相连,那么这四个点就必须是连通的(而若只有两条边就不会)。那么按原图在二分图进行连边之后就会出现一个个联通块,进行一次题目操作就会在联通块上加一条边,直到加到不能加就是完全二分图为止。那么答案就出来了:就是每个联通块完全图边数-原图已有的边数 ,所有联通块加起来就是答案。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=2e5+10; 4 typedef long long LL; 5 int n,X,Y; 6 vector<int> G[N],v; 7 bool vis[N]; 8 9 void dfs(int x,int dep) { 10 if (dep%2) X++; else Y++; 11 v.push_back(x); 12 vis[x]=1; 13 for (int i=0;i<G[x].size();i++) { 14 int t=G[x][i]; 15 if (vis[t]) continue; 16 dfs(t,dep+1); 17 } 18 } 19 20 int main() 21 { 22 cin>>n; 23 for (int i=1;i<=n;i++) { 24 int x,y; scanf("%d%d",&x,&y); 25 G[x].push_back(y+100000); 26 G[y+100000].push_back(x); 27 } 28 29 memset(vis,0,sizeof(vis)); 30 LL ans=0; 31 for (int i=1;i<=200000;i++) 32 if (G[i].size() && !vis[i]) { 33 X=0; Y=0; v.clear(); 34 dfs(i,1); 35 LL num=0; 36 for (int j=0;j<v.size();j++) num+=G[v[j]].size(); 37 ans+=(LL)X*Y-num/2; 38 } 39 cout<<ans<<endl; 40 return 0; 41 }