首页 > 其他分享 >2142. 最小矩形覆盖

2142. 最小矩形覆盖

时间:2022-11-23 16:35:58浏览次数:72  
标签:矩形 return double 最小 2142 fi PDD se 坐标

题目链接

2142. 最小矩形覆盖

已知平面上不共线的一组点的坐标,求覆盖这组点的面积最小的矩形。

输出矩形的面积和四个顶点的坐标。

输入格式

第一行包含一个整数 \(n\),表示点的数量。

接下来 \(n\) 行,每行包含两个用空格隔开的浮点数,表示一个点的 \(x\) 坐标和 \(y\) 坐标。

不用科学计数法,但如果小数部分为 \(0\),则可以写成整数。

输出格式

共 \(5\) 行,第 \(1\) 行输出一个浮点数,表示所求得的覆盖输入点集的最小矩形的面积。

接下来 \(4\) 行,每行包含两个用空格隔开的浮点数,表示所求矩形的一个顶点的 \(x\) 坐标和 \(y\) 坐标。

先输出 \(y\) 坐标最小的顶点的 \(x,y\) 坐标,如果有两个点的 \(y\) 坐标同时达到最小,则先输出 \(x\) 坐标较小者的 \(x,y\) 坐标。

然后,按照逆时针的顺序输出其他三个顶点的坐标。

不用科学计数法,精确到小数点后 \(5\) 位,后面的 \(0\) 不可省略。

答案不唯一,输出任意一组正确结果即可。

数据范围

\(3 \le n \le 50000\)

输入样例:

6
1.0 3.00000
1 4.00000
2.00000 1
3 0.00000
3.00000 6
6.0 3.0

输出样例:

18.00000
3.00000 0.00000
6.00000 3.00000
3.00000 6.00000
0.00000 3.00000

解题思路

旋转卡壳

先求出凸包,借助旋转卡壳算法,对于一条直线来说,找到距离直线最远的点,如果该直线是最终答案的某条直线的话,则经过最远点且和该直线平行的直线也一定是最终答案的某条直线,其余两条直线往中间缩即可确定出来,且同样具有单调性,同样可以用双指针算法

  • 时间复杂度:\(O(nlogn)\)

代码

// Problem: 最小矩形覆盖
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2144/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=50005;
const double eps=1e-12,inf=1e20,pi=acos(-1);
typedef pair<double,double> PDD;
int n,stk[N],top;
PDD q[N],res[4];
double min_area=inf;
PDD operator+(PDD a,PDD b)
{
	return {a.fi+b.fi,a.se+b.se};
}
PDD operator-(PDD a,PDD b)
{
	return {a.fi-b.fi,a.se-b.se};
}
PDD operator*(PDD a,double t)
{
	return {a.fi*t,a.se*t};
}
PDD operator/(PDD a,double t)
{
	return {a.fi/t,a.se/t};
}
double operator*(PDD a,PDD b)
{
	return a.fi*b.se-a.se*b.fi;
}
double operator&(PDD a,PDD b)
{
	return a.fi*b.fi+a.se*b.se;
}
double area(PDD a,PDD b,PDD c)
{
	return (b-a)*(c-a);
}
int sign(double x)
{
	if(fabs(x)<eps)return 0;
	if(x<0)return -1;
	return 1;
}
int dcmp(double x,double y)
{
	if(fabs(x-y)<eps)return 0;
	if(x<y)return -1;
	return 1;
}
double get_len(PDD a)
{
	return sqrt(a&a);
}
double project(PDD a,PDD b,PDD c)
{
	return ((b-a)&(c-a))/get_len(b-a);
}
void andrew()
{
	sort(q+1,q+1+n);
	for(int i=1;i<=n;i++)
	{
		while(top>=2&&sign(area(q[stk[top-1]],q[stk[top]],q[i]))<=0)top--;
		stk[++top]=i;
	}
	int k=top;
	for(int i=n;i>=1;i--)
	{
		while(top>k&&sign(area(q[stk[top-1]],q[stk[top]],q[i]))<=0)top--;
		stk[++top]=i;
	}
	if(n>1)top--;
}
PDD norm(PDD x)
{
	return x/get_len(x);
}
PDD rotate(PDD a,double angle)
{
	return {a.fi*cos(angle)+a.se*sin(angle),-a.fi*sin(angle)+a.se*cos(angle)};
}
void rotating_calipers()
{
	for(int i=0;i<top;i++)stk[i]=stk[i+1];
	for(int i=0,a=2,b=1,c=2;i<top;i++)
	{
		PDD d=q[stk[i]],e=q[stk[(i+1)%top]];
		while(dcmp(area(d,e,q[stk[a]]),area(d,e,q[stk[(a+1)%top]]))<0)a=(a+1)%top;
		while(dcmp(project(d,e,q[stk[b]]),project(d,e,q[stk[(b+1)%top]]))<0)b=(b+1)%top;
		if(!i)c=a;
		while(dcmp(project(d,e,q[stk[c]]),project(d,e,q[stk[(c+1)%top]]))>0)c=(c+1)%top;
		PDD x=q[stk[a]],y=q[stk[b]],z=q[stk[c]];
		double h=area(d,e,x)/get_len(e-d);
		double w=((y-z)&(e-d))/get_len(e-d);
		if(h*w<min_area)
		{
			min_area=h*w;
			res[0]=d+norm(e-d)*project(d,e,y);
			res[3]=d+norm(e-d)*project(d,e,z);
			PDD u=norm(rotate(e-d,-pi/2));
			res[1]=res[0]+u*h;
			res[2]=res[3]+u*h;
		}
	}
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lf%lf",&q[i].fi,&q[i].se);
    andrew();
    rotating_calipers();
    int k=0;
    for(int i=0;i<4;i++)
    	if(dcmp(res[i].se,res[k].se)<0||!dcmp(res[i].se,res[k].se)&&dcmp(res[i].fi,res[k].fi)<0)k=i;
    printf("%.5lf\n",min_area);
    for(int i=k,j=0;j<4;j++,i++)
    {
    	double x=res[i%4].fi,y=res[i%4].se;
    	if(!sign(x))x=0;
    	if(!sign(y))y=0;
    	printf("%.5lf %.5lf\n",x,y);
    }
    return 0;
}

标签:矩形,return,double,最小,2142,fi,PDD,se,坐标
From: https://www.cnblogs.com/zyyun/p/16918742.html

相关文章

  • 【转载】Java stream对List对象进行分组聚合操作:求和、平均值、最大值、最小值,BigDeci
    packagecom.kabka.test;importcn.hutool.json.JSONUtil;importlombok.extern.slf4j.Slf4j;importorg.junit.jupiter.api.Test;importjava.math.BigDecimal;importjav......
  • 3028. 最小圆覆盖
    题目链接3028.最小圆覆盖在一个二维平面上给定\(N\)个点,请你画出一个最小的能够包含所有点的圆。圆的边上的点视作在圆的内部。输入格式第一行包含一个整数\(N\)......
  • 最小公倍数/最大公因数
    最大公因数=两数乘积/最大公倍数于是两个问题变成了同一个问题,这边有三种方法:1.更相损减数当两数相等,直接返回否则,大数-小数,如果差==小数,返回,否则重复这一过程出口......
  • 最小生成树之普利姆算法与克鲁斯卡尔算法(贪心算法)
    最小生成树(贪心算法)概念一个有n个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有n个结点,并且有保持图连通的最少的边。连通图有多种连接方式,而其中......
  • 基础代码-最小值维护
    问题A:最小值维护时间限制:1Sec  内存限制:128MB题目描述设计一个数据结构,支持以下两种操作:1.插入一个数2.输出并删除其中最......
  • 基于最小二乘法的无线定位
    一、部分源码clc;clear;closeall;N=4;%参与定位的基站数C=3e5;%电磁波传播速度300000000m/sX=[0500050000];Y=[0050005000];x=1200;y=1600;D(1:N......
  • 输入四个数字判断最大数和最小数
    这个问题很简单我们直接看代码有好几种解决方式但我的实力实在有限暂时只会这两种请看我博客的大神们见谅#include<stdio.h>intmain(){inta,b,c,d,max=0,min=0;//......
  • Date 获取当天最小日期 与最大日期 00:00:00 59:59:99
      1date时间 00:00:00转成59:59:99  落数据发现,同事时间格式是  导致结束时间全都是00:00:00,这不是结束的最大时间格式。 于是重写了set方法,把时......
  • 【数组7】把数组排成最小的数
    题目描述输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323......
  • canvas绘制圆角矩形
     canvas绘制圆角矩形Canvas并没有提供绘制圆角矩形的方法,但是通过观察,我们可以发现,其实我们可以将圆角矩形分为四段,可以通过使用arcTo来实现我们假设起点为x,y.绘......