foj 1973 How many stars

本文介绍了一个复杂的几何问题求解算法,使用C++实现。该算法包括极角排序、通过二分查找确定点的位置等关键步骤,并通过实例演示了如何计算特定几何形状中点的相对位置。

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

//一个巨恶心的几何题目.....

#include<iostream> #include<cmath> #include<algorithm> using namespace std; #define MAXN 1001 #define INF 1000001 struct Point { __int64 x, y; double val; int id; bool operator<(const Point& p) const { return val < p.val; } }point[MAXN], cp[MAXN]; int A[MAXN][MAXN], B[MAXN][MAXN]; inline void swap(Point& p1, Point& p2) { Point tmp = p1; p1 = p2; p2 = tmp; } //通过矢量叉积求极角关系(p0p1)(p0p2) //d > 0 ,p0p1在p0p2顺时针方向上 inline __int64 multi(Point p0, Point p1, Point p2) { return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y); } inline int mod(int x, int n) { return ((x % n) + n) % n; } //二分求在直线一边的点数 int getNum(int j, int n) { int l = mod(j+1, n-1); int r = mod(j-1, n-1); if(multi(point[n-1], point[r], point[j]) < 0) return mod(r-j, n-1); if(multi(point[n-1], point[l], point[j]) > 0) return 0; while(mod(l+1, n-1) != r) { int mid = mod(l + (mod(r-l, n-1) >> 1), n-1); if(multi(point[n-1], point[mid], point[j]) > 0) r = mid; else l = mid; } return mod(l-j, n-1); } int main() { //freopen("in.txt", "r", stdin); int t, n, m, id = 1; scanf("%d", &t); int i, j; while(t--) { scanf("%d", &n); int a, b, c; for(i=0; i<n; i++) { scanf("%d%d", &a, &b); cp[i].x = a; cp[i].y = b; cp[i].id = i; } for(i=0; i<n; i++) { for(j=0; j<n; j++) { point[j] = cp[j]; if(i == j) { continue; } point[j].val = atan2((double)(point[j].y - cp[i].y), (double)(point[j].x - cp[i].x)); } swap(point[n-1], point[i]); sort(point, point + (n-1)); for(j=0; j<n-1; j++) { A[i][point[j].id] = j; B[i][point[j].id] = getNum(j, n); } } scanf("%d", &m); int tmp[6], ans; Point tra[3]; printf("Case %d:/n", id++); while(m--) { ans = 0; scanf("%d%d%d", &a, &b, &c); tra[0] = cp[a]; tra[1] = cp[b]; tra[2] = cp[c]; //确定三角形为逆时针方向 int maxx = INF, maxy = INF, tmpId = -1; for(i=0; i<3; i++) { if(tra[i].x < maxx || (tra[i].x == maxx && tra[i].y < maxy)) { tmpId = i; maxx = tra[i].x; maxy = tra[i].y; } } //tra[0]为最左下的点 swap(tra[0], tra[tmpId]); for(i=1; i<3; i++) { tra[i].val = atan2((double)(tra[i].y - tra[0].y), (double)(tra[i].x - tra[0].x)); } sort(tra+1, tra+3); tmp[0] = mod(A[tra[0].id][tra[2].id] - A[tra[0].id][tra[1].id], n-1) - 1; tmp[1] = mod(A[tra[1].id][tra[0].id] - A[tra[1].id][tra[2].id], n-1) - 1; tmp[2] = mod(A[tra[2].id][tra[1].id] - A[tra[2].id][tra[0].id], n-1) - 1; tmp[3] = n - 2 - B[tra[0].id][tra[1].id]; tmp[4] = n - 2 - B[tra[1].id][tra[2].id]; tmp[5] = n - 2 - B[tra[2].id][tra[0].id]; for(i=0; i<6; i++) { ans += tmp[i]; } ans -= 2 * (n - 3); printf("%d/n", ans); } } return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值