BZOJ 1914: [Usaco2010 OPen]Triangle Counting 数三角形

本博客探讨如何在给定的牛群坐标中计算包含原点的黄金三角形数量,采用正难则反的思路,通过极角排序与指针旋转半平面的方法解决计算几何问题。

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

Description

在一只大灰狼偷偷潜入Farmer Don的牛群被群牛发现后,贝西现在不得不履行着她站岗的职责。从她的守卫塔向下瞭望简直就是一件烦透了的事情。她决定做一些开发智力的小练习,防止她睡着了。想象牧场是一个X,Y平面的网格。她将N只奶牛标记为1…N (1 <= N <= 100,000),每只奶牛的坐标为X_i,Y_i (-100,000 <= X_i <= 100,000;-100,000 <= Y_i <= 100,000; 1 <= i <=N)。然后她脑海里想象着所有可能由奶牛构成的三角形。如果一个三角形完全包含了原点(0,0),那么她称这个三角形为“黄金三角形”。原点不会落在任何一对奶牛的连线上。另外,不会有奶牛在原点。给出奶牛的坐标,计算出有多少个“黄金三角形”。顺便解释一下样例,考虑五只牛,坐标分别为(-5,0), (0,2), (11,2), (-11,-6), (11,-5)。下图是由贝西视角所绘出的图示。 

Input

第一行:一个整数: N 第2到第N+1行: 每行两个整数X_i,Y_i,表示每只牛的坐标

Output

* 第一行: 一行包括一个整数,表示“黄金三角形的数量”

Sample Input

5
-5 0
0 2
11 2
-11 -6
11 -5



Sample Output

5

题解

计算几何,正难则反的思想。答案就是所有三角形去掉非黄金三角形。

先极角排序,对于某个点x,其与原点连线所在直线将平面划分为两部分,若一个部分有t个点,在这t个中任取2个与x显然不构成黄金三角形,,画图可知对于每个点只统计某个方向的半平面内的点就能不重不漏。具体可以用一个指针旋转半平面。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
#define pi acos(-1.0)
using namespace std;
int n;
struct dian{int x,y;double dgr;} d[100005];
ll tot,del;
bool operator < (dian i,dian j)
{return i.dgr<j.dgr;}
ll operator * (dian i,dian j)
{return (ll)i.x*j.y-(ll)i.y*j.x;}
void init()
{
	scanf("%d",&n);
	int i;
	for(i=1;i<=n;i++)
	   {scanf("%d%d",&d[i].x,&d[i].y);
	    d[i].dgr=atan2(d[i].y,d[i].x);
	   }
	sort(d+1,d+n+1);
	tot=(ll)n*(n-2)*(n-1)/6;
}
void work()
{
	int i,w=1,ct=0;
	for(i=1;i<=n;i++)
	   {while(w%n+1!=i&&d[i]*d[w%n+1]>=0)
	       {w=w%n+1;ct++;}
	    del+=(ll)ct*(ct-1)/2;
	    ct--;
	   }
	printf("%lld\n",tot-del);
}
int main()
{
	init(); work();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值