平行四边形 题解
题目id:20306
题目描述
鱼大大凭借着优秀的语文成绩当上了数学课代表?!鱼大大心想着数学和我语文好也不搭边呀,不过他的数学老师疯狂给鱼大大画饼:只要你当了数学课代表,有很多很多权利的啦......最后数学老师告诉鱼大大,人只要一行行,行行行,这句话在学科上也是一样的,语文学的好,数学也一定能学好,并给鱼大大出了一道题目,只要能完成,就让鱼大大继续当数学课代表:
在平面直角坐标系上,给出了\(n\)条线段,知道每条线段的两端点坐标,要鱼大大每次选择四条线段,使得这四条线段经过平移后的延长线能组成的平行四边形,问最多能组成多少个平行四边形?鱼大大接受了数学老师画饼行为,并为了保住数学课代表职位疯狂学习,只为了解出最多能有多少个平行四边形。
注:选过的线段不可再选,且保证除去与坐标轴平行的线段的斜率为整数。保证没有两端点相同的线段。
解题思路
在开始之前,我们需要知道斜率怎么求。
假设线段\(l\)的两个端点的坐标为\(\left(x1,y1\right)\)和\(\left(x2,y2\right)\),那线段\(l\)的斜率为\(\frac{y2-y1}{x2-x1}\)。特别地,对于\(x1=x2\)的情况,该线段\(l\)的斜率为\(\infty\)。
这题是一道贪心题,我们把每次斜率最多的线段数量\(x\)和斜率次多的线段数量\(y\)取出,那么这两条线段可以产生\(y\)个平行四边形\((\)因为\(x\)比\(y\)多而\(2\)对\(\left(x,y\right)\)可以组成一个平行四边形\()\),加完答案后将剩的\(x-y\)条线段添加。
因为该题每次取出的是最大值,所以我们用优先队列\((\)大根堆\()\)存储。
priority_queue<int,vector<int>,less<int>>q;
再配合map
存储即可。
AC Code
#include<bits/stdc++.h>
#define N 1000007
#define INF 1e18
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define IOS ios::sync_with_stdio(0),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
ll n,ans;
priority_queue<ll,vector<ll>,less<ll>>p;
map<ll,ll>mp;
int main()
{
IOS,cin>>n;
for(ll i=1,a,b,c,d;i<=n;++i)
{
cin>>a>>b>>c>>d;
if(a!=c)
++mp[(d-b)/(c-a)];
else
++mp[INF];
}
for(auto it:mp)
p.push(it.second/2);
while(p.size()>=2)
{
int x=p.top();
p.pop();
int y=p.top();
p.pop();
ans+=y;
p.push(x-y);
}
cout<<ans;
return 0;
}