P1715 [USACO16DEC] Lots of Triangles P

算法

计算几何, 容斥原理.

思路

首先考虑一个很简单的暴力, 我们枚举每个三角形的三个顶点, 然后枚举每一个点并且判断其是否在三角形内, 时间复杂度 \(\mathcal{O}(n^4)\).

然后就没有思路了, 看了下题解, 发现可以使用容斥进行优化.

如上图, 将每个点投影到 x 轴上, 那么根据容斥, \(\rm{S}_{\triangle ABC} = S_{ADFC} - S_{ABED} - S_{BCFE}\).
那么对于图形内的树的数量, 也可以如法炮制, 只需要预处理出每两个点形成的线段下方树的数量即可.
注意对于图 1, 2, \(B\) 点可能会被算进答案, 只需要判断下并删去即可.

#include "iostream"
#include "cmath"
#include "algorithm"

using namespace std;

constexpr int N = 3e2 + 10;

int n;
struct Point {
	int x, y;
	friend bool operator<(Point x, Point y) {
		if (x.x ^ y.x)
			return x.x < y.x;
		return x.y < y.y;
	}
} p[N];

void init() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i)
		scanf("%d %d", &p[i].x, &p[i].y);
	sort(p + 1, p + n + 1);
}

int cnt[N][N], ans[N]; // 两点下方点的数量.

bool check(int i, int j, int k) {
	double xi = p[i].x, yi = p[i].y, xj = p[j].x, yj = p[j].y, xk = p[k].x, yk = p[k].y;
	if (xk < xi or xk > xj)
		return 0;
	double K = (yi - yj) / (xi - xj);
	return yk < K * (xk - xi) + yi;
}

void calculate() {
	for (int i = 1; i ^ n; ++i)
		for (int j = i + 1; j <= n; ++j)
			for (int k = i + 1; k ^ j; ++k)
				cnt[i][j] += check(i, j, k);
	for (int i = 1; i ^ n - 1; ++i)
		for (int j = i + 1; j ^ n; ++j)
			for (int k = j + 1; k <= n; ++k)
				++ans[abs(cnt[i][j] + cnt[j][k] - cnt[i][k] + check(i, k, j))];
	for (int i = 0; i ^ n - 2; ++i)
		printf("%d\n", ans[i]);
}

void solve() {
	init();
	calculate();
}

int main() {
	solve();
	return 0;
}
posted @   Steven1013  阅读(5)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示