计算几何中的凸包类问题
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初学计算几何——初识凸包