AtCoder Beginner Contest 131 F - Must Be Rectangular!

二维平面矩形补全算法
本文介绍了一种解决二维平面上矩形补全问题的独特算法。通过将问题转化为二分图连通性的分析,利用深度优先搜索遍历确定每个连通块中可形成的矩形数量,最终得出在原图基础上能进行的最大操作次数。

题意:给出二维平面的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 }

 

转载于:https://www.cnblogs.com/clno1/p/11224028.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值