Largest Quadrilateral --凸包+旋转卡壳

本文介绍了一种算法,用于求解给定点集在二维平面上能构成的最大四边形面积。该算法首先计算点集的凸包,并针对不同数量的凸包顶点采用不同的策略来寻找最大面积的四边形。

题意

这题的题目意思很显然,给出多个在二维平面的点,求这些点中所能形成的四边形的最大面积

  • 首先要进行的是求这些点的凸包,在凸包上所构建的四边形中存在最大的四边形面积
  • 在形成凸包后,有下列三种情况
  • 最终所形成的凸包是一条直线,即所有点都在一条直线上,此时形成的凸包的点的个数为2,形成的四边形面积为0
  • 最后形成的凸包的点只有三个,此时要构建的是一个凹四边形。那么直接枚举在凸包里面的点,求这个点与其中两个凸包上的点的最小面积。最后用凸包三角形的面积减去这个所求的最小三角形面积即可。
  • 形成的凸包点的个数 ≥4≥44 个时,就需要用到旋转卡壳来进行求面积。首先将四边形分割成两个三角形,接下来枚举第一个点与第三个点,用旋转卡壳来定位到当前状态下的最大三角形面积。
  • 这道题的数据有坑,有重复出现的点,在对应凸包只有三个点的时候,出现重复的点直接就可以形成最大的凸包三角形面积。
  • 详情见代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uii;
typedef pair<int, int> pii;
template<typename T>
inline void rd(T& x)
{
	int tmp = 1; char c = getchar(); x = 0;
	while (c > '9' || c < '0') { if (c == '-')tmp = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	x *= tmp;
}
const int N = 1e5 + 10;
const int M = 1e5 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
int sgn(double x) {//一个数是否等于0 
	if (fabs(x) < eps) return 0;
	return x < 0 ? -1 : 1;
}
struct Point {
	ll x, y;
	Point() {}
	Point(ll x, ll y) :x(x), y(y) {}
	Point operator+(const Point& B) { return Point(x + B.x, y + B.y); }
	Point operator-(const Point& B) { return Point(x - B.x, y - B.y); }
	Point operator*(double k) { return Point(x * k, y * k); }
	Point operator/(double k) { return Point(x / k, y / k); }
	bool operator ==(const Point& B) { return sgn(x - B.x) == 0 && sgn(y - B.y) == 0; }
	bool operator <(const Point& B) { return sgn(x - B.x) < 0 || (sgn(x - B.x) == 0 && sgn(y - B.y) < 0); }
};
typedef Point Vector;//向量 
ll Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x; }

int Andrew(Point* p, int n, Point* q) {//p是原图,q是凸包图 
	sort(p, p + n, [](const Point& a, const Point& b) {
		if (a.x == b.x) return a.y < b.y;
		return a.x < b.x;
		});
	n = unique(p, p + n) - p;
	int num = 0; //凸包的点数 
	for (int i = 0; i < n; ++i) {
		while (num > 1 && sgn(Cross(q[num - 1] - q[num - 2], p[i] - q[num - 2])) <= 0) --num;
		q[num++] = p[i];
	}
	int tmp = num;
	for (int i = n - 2; i >= 0; --i) {
		while (num > tmp && sgn(Cross(q[num - 1] - q[num - 2], p[i] - q[num - 2])) <= 0) --num;
		q[num++] = p[i];
	}
	if (n > 1) --num;
	return num;
}

inline int nxt(int pos, int n) {
	return pos + 1 == n ? 0 : pos + 1;
}

ll RotateCaliper(Point p[], int n) {
	ll res = 0;
	for (int p1 = 0; p1 < n; ++p1) {
		int p2 = nxt(p1, n);
		int p4 = nxt(nxt(nxt(p1, n), n), n);
		for (int p3 = nxt(p2, n); p3 != p1; p3 = nxt(p3, n)) {
			while (nxt(p2, n) != p3 && Cross(p[p2] - p[p1], p[p3] - p[p1]) < Cross(p[nxt(p2, n)] - p[p1], p[p3] - p[p1])) p2 = nxt(p2, n);
			if (p4 == p3) p4 = nxt(p4, n);
			while (nxt(p4, n) != p1 && Cross(p[p3] - p[p1], p[p4] - p[p1]) < Cross(p[p3] - p[p1], p[nxt(p4, n)] - p[p1])) p4 = nxt(p4, n);
			res = max(res, Cross(p[p2] - p[p1], p[p3] - p[p1]) + Cross(p[p3] - p[p1], p[p4] - p[p1]));
		}
	}
	return res;
}
Point p[N], q[N];
int main() {
	//	FILE* _INPUT = freopen("input.txt", "r", stdin);
	//FILE* _OUTPUT = freopen("output.txt", "w", stdout);
	int T; rd(T);
	while (T--) {
		int n; rd(n);
		for (int i = 0; i < n; ++i) {
			rd(p[i].x); rd(p[i].y);
		}
		int tmp = n;
		n = Andrew(p, n, q);
		if (n == 2) {
			puts("0");
			continue;
		}
		else if (n == 3) {
			ll ans = Cross(q[1] - q[0], q[2] - q[0]);
			ll res = 4e18;
			int cnt0 = 0, cnt1 = 0, cnt2 = 0;
			for (int i = 0; i < tmp; ++i) {
				if (p[i] == q[0]) {
					++cnt0;
					continue;
				}
				if (p[i] == q[1]) {
					++cnt1;
					continue;
				}
				if (p[i] == q[2]) {
					++cnt2;
					continue;
				}
				for (int j = 0; j < 3; ++j) {
					ll tmp = Cross(q[nxt(j, n)] - q[j], p[i] - q[j]);
					if (tmp < 0) continue;
					res = min(res, tmp);
				}
			}
			if (cnt0 > 1 || cnt1 > 1 || cnt2 > 1) res = 0;
			ans -= res;
			if (ans & 1) printf("%lld.5", ans / 2);
			else printf("%lld\n", ans / 2);
		}
		else {
			ll ans = RotateCaliper(q, n);
			if (ans & 1) printf("%lld.5\n", ans / 2);
			else printf("%lld\n", ans / 2);
		}
	}
	return 0;
}
【电力系统】单机无穷大电力系统短路故障暂态稳定Simulink仿真(带说明文档)内容概要:本文档围绕“单机无穷大电力系统短路故障暂态稳定Simulink仿真”展开,提供了完整的仿真模型与说明文档,重点研究电力系统在发生短路故障后的暂态稳定性问题。通过Simulink搭建单机无穷大系统模型,模拟不同类型的短路故障(如三相短路),分析系统在故障期间及切除后的动态响应,包括发电机转子角度、转速、电压和功率等关键参数的变化,进而评估系统的暂态稳定能力。该仿真有助于理解电力系统稳定性机理,掌握暂态过程分析方法。; 适合人群:电气工程及相关专业的本科生、研究生,以及从事电力系统分析、运行与控制工作的科研人员和工程师。; 使用场景及目标:①学习电力系统暂态稳定的基本概念与分析方法;②掌握利用Simulink进行电力系统建模与仿真的技能;③研究短路故障对系统稳定性的影响及提高稳定性的措施(如故障清除时间优化);④辅助课程设计、毕业设计或科研项目中的系统仿真验证。; 阅读建议:建议结合电力系统稳定性理论知识进行学习,先理解仿真模型各模块的功能与参数设置,再运行仿真并仔细分析输出结果,尝试改变故障类型或系统参数以观察其对稳定性的影响,从而深化对暂态稳定问题的理解。
本研究聚焦于运用MATLAB平台,将支持向量机(SVM)应用于数据预测任务,并引入粒子群优化(PSO)算法对模型的关键参数进行自动调优。该研究属于机器学习领域的典型实践,其核心在于利用SVM构建分类模型,同时借助PSO的全局搜索能力,高效确定SVM的最优超参数配置,从而显著增强模型的整体预测效能。 支持向量机作为一种经典的监督学习方法,其基本原理是通过在高维特征空间中构造一个具有最大间隔的决策边界,以实现对样本数据的分类或回归分析。该算法擅长处理小规模样本集、非线性关系以及高维度特征识别问题,其有效性源于通过核函数将原始数据映射至更高维的空间,使得原本复杂的分类问题变得线性可分。 粒子群优化算法是一种模拟鸟群社会行为的群体智能优化技术。在该算法框架下,每个潜在解被视作一个“粒子”,粒子群在解空间中协同搜索,通过不断迭代更新自身速度与位置,并参考个体历史最优解和群体全局最优解的信息,逐步逼近问题的最优解。在本应用中,PSO被专门用于搜寻SVM中影响模型性能的两个关键参数——正则化参数C与核函数参数γ的最优组合。 项目所提供的实现代码涵盖了从数据加载、预处理(如标准化处理)、基础SVM模型构建到PSO优化流程的完整步骤。优化过程会针对不同的核函数(例如线性核、多项式核及径向基函数核等)进行参数寻优,并系统评估优化前后模型性能的差异。性能对比通常基于准确率、精确率、召回率及F1分数等多项分类指标展开,从而定量验证PSO算法在提升SVM模型分类能力方面的实际效果。 本研究通过一个具体的MATLAB实现案例,旨在演示如何将全局优化算法与机器学习模型相结合,以解决模型参数选择这一关键问题。通过此实践,研究者不仅能够深入理解SVM的工作原理,还能掌握利用智能优化技术提升模型泛化性能的有效方法,这对于机器学习在实际问题中的应用具有重要的参考价值。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值