牛客 E - 分割线
牛客 E - 分割线
极角排序,叉积
题目简述
给定平面上 n(n≤100)个互不相同的点。定义“分割线”为:由两个点确定的直线,使得分布在直线两侧的点数量相同(直线上的点不计入任何一侧)。求满足条件的无序点对数量。
核心思路
1. 直接枚举点对(暴力法)
由于 n 很小(≤100),可以直接枚举所有点对 (i, j),然后判断其他点在该直线两侧的分布是否相等。
- 用叉积判断每个点相对于直线 (i→j) 的位置:
cross = (x_k - x_i) * (y_j - y_i) - (y_k - y_i) * (x_j - x_i)cross > 0:左侧cross < 0:右侧cross == 0:在直线上
- 统计 left 和 right,若相等则答案加一。
复杂度 O(n³),对于 n=100 约 50 万次运算,完全可行。
2. 极角排序(更高效的做法,适用于更大 n)
虽然本题暴力足够,但若数据更大(如 n≤2000),可采用极角排序+双指针做到 O(n² log n)。
步骤
- 枚举直线上的一个点 P。
- 以 P 为原点,计算其他点的极角(atan2 或向量排序),并排序。
- 复制数组并加上 2π 以处理跨半圆的情况。
- 用双指针维护小于 180° 的点数,即直线一侧的点数。
- 同时需处理共线点(相同极角),统计直线上的点数 onLine。
- 判定条件:左侧点数 == 右侧点数,即
left == (n - 2 - onLine) / 2(需满足整数)。
但本题 n 很小,暴力法更为简洁,不易出错。
公式推导(供参考)
对于固定点对 (i, j),设:
left= 直线左侧点数right= 直线右侧点数onLine= 除 i,j 外还在直线上的点数(即 cross == 0 的其他点)
总点数满足:
left + right + onLine = n - 2
条件要求 left == right,即 2 * left + onLine = n - 2,等价于 (n - 2 - onLine) 为偶数。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
int n; cin >> n;
vector<pair<ll, ll>> p(n);
for(int i = 0; i < n; i ++) cin >> p[i].first >> p[i].second;
int ans = 0;
for(int i = 0; i < n; i ++) {
for(int j = i + 1; j < n; j ++) {
ll dx = p[j].first - p[i].first;
ll dy = p[j].second - p[i].second;
int left = 0, right = 0;
for(int k = 0; k < n; k ++) {
if(k == i || k == j) continue;
// 叉积:(p[k] - p[i]) × (p[j] - p[i])
ll cross = (p[k].first - p[i].first) * dy - (p[k].second - p[i].second) * dx;
if(cross > 0) left ++;
else if(cross < 0) right ++;
}
if(left == right) ans ++;
}
}
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
int _ = 1; //cin >> _;
while(_ --) solve();
return 0;
}

浙公网安备 33010602011771号