处女座的签到题

链接:https://ac.nowcoder.com/acm/contest/327/A
来源:牛客网

题目描述

平面上有n个点,问:平面上所有三角形面积第k大的三角形的面积是多少?

输入描述:

第一行T,表示样例的个数。
对于每一组样例,第一行两个整数n和k,
接下来n行,每行两个整数x,y表示点的坐标
T<=80
3<=n<=100
-109<=x,y<=109
对于每一组样例,保证任意两点不重合,且能构成的三角形的个数不小于k

输出描述:

对于每一组样例,输出第k大三角形的面积,精确到小数点后两位(四舍五入)。
示例1

输入

1
4 3
1 1
0 0
0 1
0 -1

输出

0.50

说明

样例中一共能构成3个三角形,面积分别为0.5,0.5,和1,面积第3大的为0.5
本题的坑:
1.数据过大,不能用double存,叉积返回整数,要除2之前判断一下奇偶性,补一下小数点后缀就好了
2.叉积求三角形面积,海伦公式开根号精度不能保证
3.暴力三重循环求所有三角形,筛去同一直线上的三个点的组合。同一直线上的叉积为0。
4.不能用sort排序,复杂度为O(nlogn),很可能爆时间,用快速排序求第k大或者调用函数nth_element,复杂度O(n)
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<set>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
struct node
{
    ll x;
    ll y;
};
node p[105];
ll ans[1000005];
ll s(node p1,node p2,node p3)
{
    ll chaji=(p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y);
    return abs(chaji);
}
int main()
{
    int t;
    scanf("%d",&t);
    int n,k;
    while(t--)
    {
        scanf("%d%d",&n,&k);//求第k大
        for(int i=1;i<=n;i++)
        {
            scanf("%lld%lld",&p[i].x,&p[i].y);
        }
        int x=0;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                for(int k=j+1;k<=n;k++)
                {
                    ll temp=s(p[i],p[j],p[k]);
                    if(temp) ans[x++]=temp;
                }
        nth_element(ans,ans+x-k,ans+x);///排(x+1-k)小
        if(ans[x-k]%2==1)
            printf("%lld.50
",ans[x-k]/2);
        else
            printf("%lld.00
",ans[x-k]/2);
    }
    return 0;
}
//用人话讲,排好第k+1小的元素的下标为k
//用鬼话讲,从第0个排,第k个的放在下标为k的位置
//nth_element(ans,ans+k,ans+x);
/*人话与鬼话
数组ans里,总元素个数为x,人话第a大和人话第b小的关系。
假设x=10,元素分别为1,2,3,4,5,6,7,8,9,10。
下标分别是0,1,2,3,4,5,6,7,8,9。
设a=3,求b等于多少?
人话的第三大就是8,放在下标为7的空间里。
转化成人话的就是第b小,则元素8是第8小,
∴人话的大小转化是: b=x+1-a
然而写入函数找人话的第b小是计算机鬼话从0开始排,放在b-1下标里
∴函数中间那个参数表示,人话的第b大放在下标为b-1的下标里
*/
 
原文地址:https://www.cnblogs.com/shoulinniao/p/10322399.html