有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;
}