【每日一题】【平面几何】【向量】小红的平行四边形 “现代汽车中国前瞻软件赛杯” 牛客周赛 Round 43 E题 C++/Python

“现代汽车中国前瞻软件赛杯” 牛客周赛 Round 43 E题

小红的平行四边形

题目背景

“现代汽车中国前瞻软件赛杯” 牛客周赛 Round 43

题目描述

小红在平面上有 n n n个点,她准备选择其中四个点画一个平行四边形。请你帮小红求出平行四边形的最大面积。

在这里插入图片描述

样例 #1

样例输入 #1

5
0 0
0 1
1 0
1 1
2 1

样例输出 #1

1.0
说明

选前四个点即可(正方形也是平行四边形)

做题思路

这道题需要一些前置的几何知识

首先一点就是,两个不共线的向量的叉积(向量积,外积)的几何意义是以这两个向量为邻边的平行四边形的面积
外积

为啥要向量呢?

观察到 n ≤ 1000 n\le 1000 n1000,如果要靠点去确定一个平行四边形,至少需要三个点,然后确定另一个点的位置;最后确定平行四边形的面积。

如果是三层循环枚举所有情况时间复杂度就来到了 O ( n 3 ) O(n^3) O(n3),最坏情况约为 O ( 1 0 9 ) O(10^9) O(109),会超时。

所以改点为边,两点确定一条边,那么得出所有边的时间复杂度为 O ( n 2 ) O(n^2) O(n2),暂时没有任何问题。

但如果只是简单的看成边,只知道长度是远远不够的。

因为向量计算平行四边形是比较容易的,所以往向量上考虑。

向量有长度和方向。而且这道题需要记录起点。因为形成平行四边形是靠点连线,而不可以平移向量。

又知道平行四边形的长度对边相同且平行,所以同一长度且平行的向量(边)才能形成平行四边形。

这里开一个map,键为向量的长度和方向(即坐标),值为坐标和起点。

如果有两个坐标相同的向量,那么如何去算平行四边形呢?
因为都记录了向量的起点,那么两个起点能构成新向量,新向量和两个坐标相同的向量(拿一个)进行外积就可以得到新向量和旧向量形成的平行四边形的面积。

那么记录面积最大的即可。

有个坑点就是其实答案是整数,所以小数位一定是.0

原因是坐标为整数,向量外积也是整数,那么面积也一定是整数。


分析一个大佬JinYuManTang的题解
原文:
由于需要三个点才能计算平行四边形面积,枚举点时间复杂度不符合要求,所以我们考虑枚举边。我们对每两个点构成的向量用哈希表分组,注意向量的方向性。这里不用存下每组所有的向量然后进行排序,只需要维护一个最大值和最小值,不过需要用到一点简***面几何。

我们将当前分组的向量平移到原点,由于需要求每组向量之间能够组成的最大面积(如图中的红色面积),这可以拆成两个平行四边形面积之和(如图中绿色的S1和S2)。由于S是用叉积计算的(带正负),所以其实红色面积是S2 - S1。因此,我们只需要维护每组S的最大值和最小值,两者之差即为该组的最大面积。

作者:JinYuManTang
链接:https://www.nowcoder.com/discuss/622155303887396864?sourceSSR=users
来源:牛客网

from collections import defaultdict
n = int(input())
a = [list(map(int, input().split())) for _ in range(n)]
mx, mn = defaultdict(lambda: -10 ** 18), defaultdict(lambda: 10 ** 18)
res = 0
for i in range(n):
    x1, y1 = a[i]
    for j in range(i):
        x2, y2 = a[j]
        dx, dy = x1 - x2, y1 - y2
        if dx > 0: dx, dy = -dx, -dy
        s = dy * x1 - dx * y1
        p = (dx, dy)
        mx[p], mn[p] = max(mx[p], s), min(mn[p], s)
        res = max(res, mx[p] - mn[p]) 
print(str(res) + '.0' if res else -1)

作者:JinYuManTang
链接:https://www.nowcoder.com/discuss/622155303887396864?sourceSSR=users
来源:牛客网

这里对红色面积为什么是 S 2 − S 1 S2-S1 S2S1做个较为详细的解释

在这里插入图片描述

S 1 = a ⃗ × c ⃗ S1 = \vec{a}\times \vec{c} S1=a ×c
S 2 = a ⃗ × b ⃗ S2 = \vec{a}\times \vec{b} S2=a ×b
d ⃗ = b ⃗ − c ⃗ \vec{d} = \vec{b} - \vec{c} d =b c
红色面积 = a ⃗ × d ⃗ = a ⃗ × ( b ⃗ − c ⃗ ) = a ⃗ × b ⃗ − a ⃗ × c ⃗ = S 2 − S 1 红色面积 = \vec{a}\times \vec{d} = \vec{a}\times(\vec{b} - \vec{c}) = \vec{a}\times \vec{b} - \vec{a}\times \vec{c} = S2-S1 红色面积=a ×d =a ×(b c )=a ×b a ×c =S2S1

代码

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <tuple>
#include <cstring>
#define int long long
using namespace  std;
const int N = 1e5+10;
inline bool cmp(vector<int>a,vector<int> b){
    int x=a[2],y=a[3],xx=b[2],yy=b[3];
    int dx=a[0],dy=a[1];
    return dx*y-dy*x < dx*yy-dy*xx;
} 
int a[N],b[N];
int n;
map<pair<int,int> , vector<vector<int>>> mp;
signed main(){
    cin >> n;
    for(int i=1;i<=n;i++)cin >> a[i] >> b[i];
    int x,y;
    for(int i=1;i<=n;i++){
        for(int j=1+i;j<=n;j++){
            x = a[i]-a[j] , y = b[i] - b[j];
            if(x<0)x*=-1,y*=-1;
            mp[make_pair(x,y)].push_back({x,y,a[i],b[i]});
        }
    }
    int ans = 0;
    for(auto i : mp){
        auto v = i.second;
        sort(v.begin(),v.end(),cmp);
        int x=v[0][2],y=v[0][3],xx=v.back()[2],yy=v.back()[3];
        int dx = xx-x, dy = yy-y;
        ans=max(ans,abs(i.first.second*dx - i.first.first*dy));
    }
    if(!ans)cout << -1;
    else cout << ans << ".0";
    return 0;
}
  • 27
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值