hdu 3629 极坐标排序

/*
* hdu3629/linux.cpp
* Created on: 2011-8-25
* Author : ben
*/
#include
<cstdio>
#include
<algorithm>
#include
<cstring>
#include
<cmath>
using namespace std;

const int MAXN = 705;
const double PI = acos(-1);

typedef
struct {
int x;
int y;
} MyPoint;

int N;
MyPoint points[MAXN];
double angs[MAXN][MAXN];

int findindex(double *angarray, double ang) {
int low, mid, high;
low
= 0;
high
= N - 2;
while (low <= high) {
mid
= (low + high) / 2;
if (angarray[mid] > ang) {
high
= mid - 1;
}
else {
low
= mid + 1;
}
}
return low;
}

void work() {
int T, i, j, tempindex, center;
long long tu, ao, num, tempnum;
double oppang;
scanf(
"%d", &T);
while (T--) {
scanf(
"%d", &N);
for (i = 0; i < N; i++) {
scanf(
"%d%d", &points[i].x, &points[i].y);
}
tu
= ((long long) N) * (N - 1) * (N - 2) * (N - 3) / 24;
for (i = 0; i < N; i++) {
tempindex
= 0;
for (j = 0; j < N; j++) {
if (j != i) {
angs[i][tempindex
++] = atan2(points[j].y - points[i].y,
points[j].x
- points[i].x);
}
}
sort(angs[i], angs[i]
+ N - 1);
}
ao
= ((long long) (N - 1)) * (N - 2) * (N - 3) / 6;
for (center = 0; center < N; center++) {
tempnum
= 0;
for (i = 0; i < N - 1; i++) {
if (angs[center][i] > 0) {
oppang
= angs[center][i] - PI;
}
else {
oppang
= angs[center][i] + PI;
}
j
= findindex(angs[center], oppang);
num
= (j + N - i - 2) % (N - 1);
tempnum
+= num * (num - 1) / 2;
}
tu
-= ao - tempnum;
}
printf(
"%I64d\n", tu);
}
}

int main() {
#ifndef ONLINE_JUDGE
freopen(
"data.in", "r", stdin);
#endif
work();
return 0;
}

  

这题是去年网络赛的一题,当时不会,王老师想到一个n^3logn的算法,我也没敢打,比赛完后,看解题报告,标程是n^2logn的。前天模拟赛再次遇到这道题,照去年解题报告中方法打了半天,一直是TLE,网上找大牛代码,也就是没有他们写得精练而已。昨天花了一点时间优化,终于不TLE,成WA了。今天下午继续改,最后发现错误竟在于排序用的比较函数写得不对!以后还是用C++吧,C的排序函数真容易出错……

 

题目意思是给N个点,问这些点能构成多少个凸四边形。逆向思维,如果四个点不能组成凸四边形,则必然是其中三个点组成一个三角形,另一个点在该三角形内部。
于是我们可以O(n)枚举一个点作为内部中心,试图从其他的点里选出三个来,组成三角形把它包围住,看看有多少种可能的选择。
继续观察发现,如果三个点不能圈住中心点,则必然是存在一条通过中心点的直线,使得这三点都在直线的同侧。
于是我们可以把所有点(除了中心点)按极角排序,然后线性转圈扫描一下就可以统计出来了。总的复杂度是O(n^2*logn)

 

posted @ 2011-08-27 16:29  moonbay  阅读(342)  评论(0编辑  收藏  举报