51nold 1451 合法三角形【数学几何】

本文介绍了一种算法,用于计算给定点集中能构成非零面积三角形的数量。通过排除三点共线的情况,利用斜率比较和数学组合实现高效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来源:  CodeForces
基准时间限制:1 秒 空间限制:131072 KB 分值: 80  难度:5级算法题
 收藏
 关注

有n个不同的点,问有多少组三元组能构成面积非0的三角形。

Input
单组测试数据。
第一行一个整数n (1 ≤ n ≤ 2000),表示点的数目。
接下来n行,每行包含两个整数 xi, yi ( -100 ≤ xi, yi ≤ 100),表示第i个点的坐标。输入保证点是两两不同的。
Output
输出合法的三角形数目。
Input示例
4
0 0
1 1
2 0
2 2
Output示例
3



思路:

就是求三点不共线的个数 = 组合总数 -  三点共线个数

-.-三点共线可以两点到另一点的斜率来判断-.-


代码:

#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
struct node{
	short x,y;
}dian[2222];
bool cmp(node xx,node yy)
{
	return xx.x<yy.x;
}
int lp,n;
int hh[220],li[220];
struct nn{
    int x,y;
}ko[2222];
bool cc(nn xx,nn yy)
{
    if (xx.x!=yy.x)
        return xx.x<yy.x;
    return xx.y<yy.y;
}
short gcd(short a,short b)
{
    if (a<b)
    {
        short c;
        c=a;
        a=b;
        b=c;
    }
    if (a%b==0)
        return b;
    else
        return gcd(b,a%b);
}
LL gg(int xx)//不平行于x,y的共线
{
    short x,y,p;
    lp=0;
    for (int i=xx+1;i<=n;i++)
    {
        x=dian[i].x-dian[xx].x;
        y=dian[i].y-dian[xx].y;
        if (x==0||y==0)
            continue;
        p=gcd(abs(x),abs(y));
        x/=p;y/=p;
        ko[lp].x=x;
        ko[lp++].y=y;
    }
    sort(ko,ko+lp,cc);
    LL ans=0;
    int k=1;
    for (int i=1;i<lp;i++)
    {
        if (ko[i].x==ko[i-1].x&&ko[i].y==ko[i-1].y)
            k++;
        else
        {
            if (k>1)
            ans+=k*(k-1)/2;
            k=1;
        }
    }
    if (k>1)
        ans+=k*(k-1)/2;
    return ans;
}
void init()
{
    memset(hh,0,sizeof(hh));
    memset(li,0,sizeof(li));
    for (int i=1;i<=n;i++)
    {
        if (dian[i].x<0)
            hh[100-dian[i].x]++;
        else
            hh[dian[i].x]++;
        if (dian[i].y<0)
            li[100-dian[i].y]++;
        else
            li[dian[i].y]++;
    }
}
LL hang()//x相同
{
    LL ans=0,k;
    for (int i=0;i<202;i++)
    {
        if (hh[i]>2)
        {
            k=hh[i]*(hh[i]-1)*(hh[i]-2)/6;
            ans+=k;
        }
    }
    return ans;
}
LL lie()//y相同
{
    LL ans=0,k;
    for (int i=0;i<202;i++)
    {
        if (li[i]>2)
        {
            k=li[i]*(li[i]-1)*(li[i]-2)/6;
            ans+=k;
        }
    }
    return ans;
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%hd%hd",&dian[i].x,&dian[i].y);
 	sort(dian+1,dian+1+n,cmp);
 	LL ans=0;
 	for (int i=1;i<n-1;i++)
    {
        ans+=gg(i);
    }
    LL io;
    io=(LL)n*(n-1)*(n-2)/6;
    io-=ans;
    init();
    io-=hang();
    io-=lie();
    printf("%lld\n",io);
 	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值