hdoj 5784 && 极角排序
2016-08-05 15:36
357 查看
How Many Triangles
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 767 Accepted Submission(s): 249
Problem Description
Alice has n points in two-dimensional plane. She wants to know how many different acute triangles they can form. Two triangles are considered different if they differ in at least one point.
Input
The input contains multiple test cases.
For each test case, begin with an integer n,
next n lines each contains two integers xi and yi.
3≤n≤2000
0≤xi,yi≤1e9
Any two points will not coincide.
Output
For each test case output a line contains an integer.
Sample Input
3
1 1
2 2
2 3
3
1 1
2 3
3 2
4
1 1
3 1
4 1
2 3
Sample Output
0
1
2
数一数锐角的数量A和直角+钝角的数量B,那么答案就是(A-2B)/3。暴力算的话是$O(n^3)$的。使用极角排序+two pointers就可以做到$O(n^2log\ n)$。 这边钝角指代范围在90度到180度之间的角(不包括90和180)。
直接统计锐角三角形较困难,考虑问题的反面,统计直角三角形、钝角三角形、平角三角形(暂时这么叫吧QAQ)。
首先枚举三角形的一个端点A,对其他点进行象限为第一关键字,极角为第二关键字排序。
然后使用三个指针,进行O(n)的扫描。
具体做法为用 i 指针指向三角形的第二个端点B。我们可以假想通过平移和旋转,把A点置于平面直角坐标系的原点,把B点置于x轴的正方向。那么可以与AB组成钝角或直角的点就在三四象限或者y轴。
将 j 指针指向第一象限内可以组成锐角的最靠后的点,将k指针从j + 1 开始扫描至最后一个可以组成钝角的点,然后统计对答案的贡献。
之后将 i 指针 +1,继续扫描。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const double eps = 1e-8;
struct point {
long long x, y;
int f;//代表在哪一个象限
friend point operator - (point a, point b) {
return (point){a.x-b.x, a.y-b.y};
}
}a[2005], b[2005];
point s;
int n, m;
long long cross(point a, point b, point c) {//ab X ac
return (b.x-a.x) * (c.y-a.y) - (b.y-a.y) * (c.x-a.x);
}
int cal(point a) {//计算象限
if(a.x > 0 && a.y >= 0) return 1;
if(a.x <= 0 && a.y > 0) return 2;
if(a.x < 0 && a.y <= 0) return 3;
if(a.x >= 0 && a.y < 0) return 4;
}
bool cmp(const point a, const point b) {//先按象限排序,再按极角排序
if(a.f < b.f) return true;
if(a.f > b.f) return false;
long long tmp = cross(s, a, b);
if(tmp > 0) return true;
return false;
}
bool ok(point a, point b, point c) {
long long tmp = (b.x-a.x) * (c.x-a.x) + (b.y-a.y) * (c.y - a.y);
if(tmp > 0) return true;
return false;
}
int main() {
while(~scanf("%d", &n)) {
for(int i = 0; i < n; i++) {
scanf("%I64d%I64d", &a[i].x, &a[i].y);
}
long long sum = 0;//统计除了锐角三角形的其他三角形的个数
for(int p = 0; p < n; p++) {//枚举三角形的一个顶点
s = a[p];
m = 0;
for(int i = 0; i < n; i++) {
if(i != p) b[m++] = a[i];
}
for(int i = 0; i < m; i++) {
b[i].f = cal(b[i]-s);
}
sort(b, b+m, cmp);//极角排序
//two pointers
int i = 0, j = 0, k = 0;
while(j < m && ok(s, b[i], b[j]) && cross(s, b[i], b[j]) >= 0) {
j++;
}
if(j == m) continue;
k = j; j--;
while(i < m) {
if(!ok(s, b[i], b[k])) {
while(k < m-1 && !ok(s, b[i], b[k+1])) k++;
sum += k - j;
}
i++;
if(j < i) j = i;
while(j < m-1 && ok(s, b[i], b[j+1]) && cross(s, b[i], b[j+1]) > 0) {
j++;
}
if(k <= j) k = j + 1;
if(k >= m) break;
}
}
long long ans = (long long)1 * n * (n-1) * (n-2) / 6;
ans -= sum;
printf("%I64d\n", ans);
}
return 0;
}
相关文章推荐
- POJ 2007 Scrambled Polygon(极角排序)
- UVALive 4617 Simple Polygon(顺/逆时针输出所有点/极角排序)
- POJ1696-Space Ant
- HDU-3629-Convex-计算几何
- hdu 5738 Eureka 极角排序 计数
- 极角排序合集
- HDU 5032 Always Cook Mushroom(极角排序, 树状数组)
- BZOJ 1914: [Usaco2010 OPen]Triangle Counting 数三角形
- 极角排序
- hdu 5784 How Many Triangles 极角排序计算锐角直角钝角
- 极角排序(主要用于凸包问题)
- hdu6127-!!多校7&极角排序&问题转化-Hard challenge
- (2017多校训练第七场)HDU - 6127 Hard challenge 极角排序+尺取法
- 2017杭电多校第七场1008 Hard challenge(级角排序)HDU 6127
- poj 1330 Nearest Common Ancestors
- HDU 2647 Reward【拓扑排序】
- Python-被调用函数中获取调用函数信息(转)
- PHP开发代码规范
- C++类的静态成员
- NBUT 1457 Sona (莫队算法)