计算几何中的凸包类问题

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算几何中的凸包类问题相关的知识,希望对你有一定的参考价值。

计算几何中的凸包类问题

P2116 城墙

求距离凸多边形为 L L L的最小外围周长。

a n s = ans= ans=凸包周长+ 2 π L 2\\pi L 2πL

图参考题解区。

至于圆弧周长等于 2 π L 2\\pi L 2πL ,是因为内角和为 360 360 360,这个容易证得,题解区也有。

P4166 [SCOI2007]最大土地面积

求四个点组成得最大多边形面积。

结论:若凸包点数大于3,则这四个点一定都在凸包上。

若凸包点数小于3,则答案为0。

若凸包点数等于3,则该四边形是一个凹四边形,凸包上的3个点会和不在凸包上的点组成一个凹四边形,枚举不在凸包上点计算即可。

凸包点数大于3时,考虑枚举对角线 i , j i,j i,j ,然后类似旋转卡壳扫 i , x , j i,x,j i,x,j 这个三角形的最大面积, i , j , y i,j,y i,j,y 这个三角形的最大面积。

然后求和取最大值即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=2e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
struct P{
    double x,y;
    int id;
}a[N],s[N];
int top,n;
double cross(P a,P b,P c){
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
double dis(P a,P b){
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp(P u,P v){
    double t=cross(u,v,a[1]);
    return t>0||(t==0&&dis(u,a[1])<dis(v,a[1]));
}
void graham(){
    s[top=1]=a[1];
    for(int i=2;i<=n;){
        if(top>1&&cross(s[top-1],a[i],s[top])>=0) top--;
        else s[++top]=a[i++];
    }
}
double rt_cp(){
	//s[top+1]=s[1];
		double ans=0;
	if(top<3) return 0;
	else if(top==3){
		ll mn=1e18;
		ans=abs(cross(s[1],s[2],s[3]));
		for(int i=1;i<=n;i++){
			if (s[1].id==a[i].id||s[2].id==a[i].id||s[3].id==a[i].id) continue;
			ll s1=abs(cross(a[i],s[1],s[2]));
			ll s2=abs(cross(a[i],s[2],s[3]));
			ll s3=abs(cross(a[i],s[3],s[1]));
			mn=min({mn,s1,s2,s3});		
		}
		if(mn!=1e18) ans-=mn;
		else ans=0;
	}
	else {
			for(int i=1;i<=top;i++){
		int x=i%top+1,y=(i+2)%top+1;
		for(int j=i+2;j<=top;j++){
while(x%top+1!=j&&fabs(cross(s[i],s[x+1],s[j]))>fabs(cross(s[i],s[x],s[j])))
		x=x%top+1;
while(y%top+1!=i&&fabs(cross(s[i],s[j],s[y+1]))>fabs(cross(s[i],s[j],s[y])))
		y=y%top+1;	
		ans=max(ans,fabs(cross(s[i],s[x],s[j]))+fabs(cross(s[i],s[j],s[y])));	
		}
	}
	}
	return ans/2.0;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y),a[i].id=i;
    int id=1;
    for(int i=2;i<=n;i++) 
        if(a[i].x<a[id].x||(a[i].x==a[id].x&&a[i].y<a[id].y)) id=i;
    swap(a[1],a[id]);sort(a+2,a+n+1,cmp);graham();
    printf("%.3f\\n",rt_cp());
}

2019ICPC TaiBei L- Largest Quadrilateral

双倍经验,不过此题卡 d o u b l e double double ,全部换成long long,因为答案要么.0,要么时.5 所以特判下即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=5e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
struct P{
    ll x,y;
    int id;
}a[N],s[N];
int top,n;
ll cross(P a,P b,P c){
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
ll dis(P a,P b){
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp(P u,P v){
    ll t=cross(u,v,a[1]);
    return t>0||(t==0&&dis(u,a[1])<dis(v,a[1]));
}
void graham(){
    s[top=1]=a[1];
    for(int i=2;i<=n;){
        if(top>1&&cross(s[top-1],a[i],s[top])>=0) top--;
        else s[++top]=a[i++];
    }
}
void rt_cp(){
	//s[top+1]=s[1];
	ll ans=0;
	if(top<3) {
		printf("0\\n");return;
	}
	else if(top==3){
		ll mn=1e18;
		ans=abs(cross(s[1],s[2],s[3]));
		for(int i=1;i<=n;i++){
			if (s[1].id==a[i].id||s[2].id==a[i].id||s[3].id==a[i].id) continue;
			ll s1=abs(cross(a[i],s[1],s[2]));
			ll s2=abs(cross(a[i],s[2],s[3]));
			ll s3=abs(cross(a[i],s[3],s[1]));
			mn=min({mn,s1,s2,s3});		
		}
		if(mn!=1e18) ans-=mn;
		else ans=0;
	}
	else { s[++top]=s[1];
			for(int i=1;i<=top;i++){
		int x=i%top+1,y=(i+2)%top+1;
		for(int j=i+2;j<=top;j++){
while(x%top+1!=j&&abs(cross(s[i],s[x+1],s[j]))>abs(cross(s[i],s[x],s[j])))
		x=x%top+1;
while(y%top+1!=i&&abs(cross(s[i],s[j],s[y+1]))>abs(cross(s[i],s[j],s[y])))
		y=y%top+1;	
		ans=max(ans,abs(cross初学计算几何——初识凸包

计算几何——凸包问题

计算几何——凸包问题

Cows 计算几何 求凸包 求多边形面积

[HDU4316]Mission Impossible(计算几何/凸包/半平面交)

P2742 [USACO5.1]圈奶牛Fencing the Cows /模板二维凸包(计算几何)(凸包)