凸包

模版题: http://acm.hdu.edu.cn/showproblem.php?pid=1392(Graham算法)

#include<bits/stdc++.h>
using namespace std;
const int M=1e3+3;
struct tu{
    double x,y;
    tu friend operator -(tu a,tu b){
        return {a.x-b.x,a.y-b.y};
    }
}p[M],s[M];
double X(tu a,tu b){
    return a.x*b.y-a.y*b.x;
}
double dis(tu a,tu b){
    a=a-b;
    return sqrt(a.x*a.x+a.y*a.y);
}
bool cmp(tu a,tu b){
    int x=X(a-p[1],b-p[1]);
    if(x>0||x==0&&dis(a,p[1])<dis(b,p[1]))
        return 1;
    return 0;
}

int main(){
    int n;
    while(~scanf("%d",&n)&&n){
        for(int i=1;i<=n;i++)
            cin>>p[i].x>>p[i].y;


        int k=1;
        if(n==1){
            printf("0.00\n");
            continue;
        }
        else if(n==2){
            printf("%.2lf\n",dis(p[1],p[2]));
            continue;
        }
        for(int i=2;i<=n;i++)
            if(p[i].y<p[k].y||p[i].y==p[k].y&&p[i].x<p[k].x)
                k=i;
        swap(p[1],p[k]);
        sort(p+2,p+1+n,cmp);
        s[1]=p[1],s[2]=p[2];
        int tot=2;
        for(int i=3;i<=n;i++){
            while(tot>=2&&X(s[tot]-s[tot-1],p[i]-s[tot-1])<=0)
                tot--;
            s[++tot]=p[i];
        }

        double ans=dis(s[1],s[tot]);
       /// cout<<ans<<endl;
        for(int i=2;i<=tot;i++)
            ans+=dis(s[i],s[i-1]);
        printf("%.2lf\n",ans);
    }
    return 0;
}
View Code

 任意多边形的面积

struct tu {
    double x, y;
};

//计算任意多边形的面积,顶点按照顺时针或者逆时针方向排列
double polygon_area(tu *p, int n)
{
    if(n < 3) return 0;

    double sum = 0;
    p[n + 1] = p[1];
    for(int i = 1; i <= n; i++)
        sum += p[i].x * p[i + 1].y - p[i].y * p[i + 1].x;//可以理解为不管这个多边形在哪,都以原点为分割点,就算原点在外面也可以算出,因为有正负可以抵消掉多余的
    sum = fabs(sum / 2.0);
    return sum;
}

求面积均匀的多边形重心

#include<bits/stdc++.h>
using namespace std;
struct node{
    double x,y;
    node friend operator -(node a,node b)
    {
        return {a.x-b.x,a.y-b.y};
    }
    double friend operator *(node a,node b)//对*进行重载  node*node 相当于X乘 
    {
        return a.x*b.y-a.y*b.x;
    }
}a[1000010];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].y;
        
        double S=0,X=0,Y=0;
        for(int i=2;i<n;i++)
        {
            double x=(a[i]-a[1])*(a[i+1]-a[1]);//这个乘和下面的不一样,这时X乘,求出三角形面积 
            X+=(a[1].x+a[i].x+a[i+1].x)*x;//重心(没除以3)乘以面积 
            Y+=(a[1].y+a[i].y+a[i+1].y)*x;
            S+=x;
        }
        printf("%.2lf %.2lf\n",X/S/(double)3,Y/S/(double)3);//除以3为重心 
     } 
    return 0;
}
View Code

 

Melkman算法

例题:http://poj.org/problem?id=2187

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long ll;
const int M=1e5+5;
struct node{
    ll x,y;
    node friend operator-(node a,node b){
        return {a.x-b.x,a.y-b.y};
    }
    bool friend operator==(node a,node b){
        return a.x==b.x&&a.y==b.y;
    }
    
}a[M],p[M<<1];
bool cmp(node a,node b){
    return a.x-b.x<0||a.x==b.x&&a.y-b.y<0;
}
ll dis(node a,node b){
    node c=a-b;
    return c.x*c.x+c.y*c.y;
}
ll X(node a,node b){
    return a.x*b.y-a.y*b.x;
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%lld%lld",&a[i].x,&a[i].y);
    sort(a,a+n,cmp);
    n=unique(a,a+n)-a;
    int m=0;
    for(int i=0;i<n;i++){
        while(m>1&&X(p[m-1]-p[m-2],a[i]-p[m-2])<=0)
            m--;
        p[m++]=a[i];
    }
    int k=m;
    for(int i=n-2;i>=0;i--){
        while(m>k&&X(p[m-1]-p[m-2],a[i]-p[m-2])<=0)
            m--;
        p[m++]=a[i];
    }
    n=m;
    if(n>1)
        n--;
    if(n==1)
        return puts("0"),0;
    if(n==2)
        return printf("%lld\n",dis(p[0],p[1])),0;
    ll ans=0;
    p[n]=p[0];
    int j=1;
    for(int i=0;i<n;i++){
        while(X(p[i+1]-p[i],p[j]-p[i])-X(p[i+1]-p[i],p[j+1]-p[i])<0)
            j=(j+1)%n;
        ll d1=dis(p[i],p[j]);
        ll d2=dis(p[i+1],p[j]);
        ans=max(ans,max(d1,d2));
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

https://codeforces.com/gym/101635 

分析:旋转卡壳求最小直径

#include<bits/stdc++.h>
using namespace std;
const int M=2e5+5;
struct  node{
    double x,y;
    node friend operator -(node a,node b){
        return {a.x-b.x,a.y-b.y};
    }
    bool friend operator ==(node a,node b){
        return a.x==b.x&&a.y==b.y;
    }
 
}a[M],p[M<<1];
bool cmp(node a,node b){
    return a.x-b.x<0||a.x==b.x&&a.y-b.y<0;
}
double X(node a,node b){
    return a.x*b.y-a.y*b.x;
}

double dis(node a,node b){
    node c=a-b;
    return c.x*c.x+c.y*c.y;
}
int main(){
    int n;
    double R;
    scanf("%d%lf",&n,&R);
    for(int i=0;i<n;i++){
        scanf("%lf%lf",&a[i].x,&a[i].y);
    }
    sort(a,a+n,cmp);
    n=unique(a,a+n)-a;
    //cout<<n<<endl;
    int m=0;
    for(int i=0;i<n;i++){
        while(m>1&&X(p[m-1]-p[m-2],a[i]-p[m-2])<=0)
            m--;
        p[m++]=a[i];
    }
    int k=m;
    for(int i=n-2;i>=0;i--){
        while(m>k&&X(p[m-1]-p[m-2],a[i]-p[m-2])<=0)
            m--;
        p[m++]=a[i];
    }
    if(n>1)
        m--;
    n=m;
    if(n<=2)
        return printf("0.000000000"),0;
    int j=1;
    double ans=2.0*R;
    p[n]=p[0];
    for(int i=0;i<n;i++){
        while(X(p[i+1]-p[i],p[j+1]-p[i])-X(p[i+1]-p[i],p[j]-p[i])>0)///每次找离直线i-i+1最远的点,也即为符合条件的点 
            j=(j+1)%n;
        double d=sqrt(dis(p[i],p[i+1]));
        double h=1.0*fabs(X(p[i+1]-p[i],p[j]-p[i]))/d;
        ans=min(ans,h);
    }
    printf("%.10f\n",ans);
    return 0;
}
Mlekman算法

 

posted @ 2019-12-01 13:48  starve_to_death  阅读(117)  评论(0编辑  收藏  举报