平行四边形 题解

题目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;
}
posted @ 2024-07-31 18:07  Firra3500  阅读(9)  评论(0编辑  收藏  举报