洛谷P4166 [SCOI2007]最大土地面积

将四边形拆成两个三角形。旋转卡壳经典题。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef int lint;
const int maxn = 2001;
const double eps = 1e-12;
const double PI = acos(-1.0);
int sgn(double x)
{
    if(fabs(x) < eps)return 0;
    if(x < 0)return -1;
    else return 1;
}
struct Point
{
    double x,y;
    Point(){}
    Point(double _x,double _y)
    { x = _x;y = _y;
    }
    Point operator -(const Point &b)const
    {
        return Point(x - b.x,y - b.y);
    }
//叉积
    double operator ^(const Point &b)const
    {
        return x*b.y - y*b.x; }
//点积
    double operator *(const Point &b)const
    {
        return x*b.x + y*b.y; }
//绕原点旋转角度B(弧度值),后x,y的变化
    void transXY(double B)
    {
        double tx = x,ty = y; x = tx*cos(B) - ty*sin(B);
        y = tx*sin(B) + ty*cos(B);
    }
};
struct Line
{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e)
    { s = _s;e = _e;
    }
    pair<int,Point> operator &(const Line &b)const
    {
        Point res = s;
        if(sgn((s-e)^(b.s-b.e)) == 0)
        {
            if(sgn((s-b.e)^(b.s-b.e)) == 0)
                return make_pair(0,res);//重合
            else return make_pair(1,res);//平行
        }
        double t = ((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
        res.x += (e.x-s.x)*t;
        res.y += (e.y-s.y)*t;
        return make_pair(2,res);
    }
};
Point PointToLine(Point P,Line L)
{
    Point result;
    double t = ((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));
    result.x = L.s.x + (L.e.x-L.s.x)*t;
    result.y = L.s.y + (L.e.y-L.s.y)*t;
    return result;
}
double dist(Point a,Point b)
{
    return sqrt((a-b)*(a-b));
}
int dist2(Point a,Point b)
{
    return (a-b)*(a-b);
}
Point lis[maxn];
int Stack[maxn],top;
//相对于list[0]的极角排序

bool _cmp(Point p1,Point p2)
{
    double tmp = (p1-lis[0])^(p2-lis[0]);
    if(sgn(tmp) > 0)return true;
    else if(sgn(tmp) == 0 && sgn(dist(p1,lis[0]) - dist(p2,lis[0])) <= 0)
        return true;
    else return false;
}
void Graham(int n)
{
    Point p0;
    int k = 0;
    p0 = lis[0];
//找最下边的一个点
    for(int i = 1;i < n;i++)
    {
        if( (p0.y > lis[i].y) || (p0.y == lis[i].y && p0.x > lis[i].x) )
        {
            p0 = lis[i];
            k = i;
        }
    }
    swap(lis[k],lis[0]);
    sort(lis+1,lis+n,_cmp);
    if(n == 1)
    {
        top = 1;
        Stack[0] = 0;
        return; }
    if(n == 2)
    {
        top = 2;
        Stack[0] = 0;
        Stack[1] = 1;
        return ; }
    Stack[0] = 0;
    Stack[1] = 1;
    top = 2;
    for(int i = 2;i < n;i++)
    {
        while(top > 1 &&sgn((lis[Stack[top-1]]-lis[Stack[top-2]])^(lis[i]-lis[Stack[top-2]])) <=0)
            top--;
        Stack[top++] = i;
    }
}
lint ans1[maxn][maxn],ans2[maxn][maxn],flag1[maxn][maxn],flag2[maxn][maxn];
void rotating_calipers(Point p[],int n)
{
    Point v;
    for( int i = 0;i < n;i++ ){
        lint cur = (i+2)%n;
        lint cur2 = i;
        for( int j = i+2; j < n ;j++ ){
            if( i == 0 && j == n-1 ) break;
            while( ((p[i] - p[j])^( p[(cur+1)%n] - p[cur] )) < 0 ) cur = (cur+1)%n;
            while( ((p[i] - p[j])^( p[(cur2+1)%n]-p[cur2] )) > 0 ) cur2 = (cur2+1)%n;
            ans1[i][j] = cur;flag1[i][j] = 1;
            ans2[i][j] = cur2;flag2[i][j] = 1;
        }
    }
    return;
}
Point p[maxn];
int main(){
    lint n;
    double x,y;
    lint tot = 0;
    scanf("%d",&n);
    for( lint i = 1;i <= n;i++ ){
        scanf("%lf%lf",&x,&y);
        lis[tot++] = Point( x,y );
    }
    Graham(n);
    for( lint i = 0;i < top;i++ ){
        p[i] = lis[Stack[i]];
    }
    rotating_calipers( p,top );
    double ans  = 0;
    for( lint i = 0;i < top;i++ ){
        for( lint j = 0;j < top;j++ ){
            if( flag1[i][j]&&flag2[i][j] ){
                Point x = p[i] - p[j];
                Point y1 = p[ans1[i][j]] - p[j];
                Point y2= p[ ans2[i][j] ] - p[j];
                ans = max( ans,(abs((x^y1)) + abs((x^y2)))/2 );
            }
        }
    }
    printf("%.3lf\n",ans);
    return 0;
}

 水平排序版本

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef int lint;
const int maxn = 2001;
const double eps = 1e-12;
const double PI = acos(-1.0);
int sgn(double x)
{
    if(fabs(x) < eps)return 0;
    if(x < 0)return -1;
    else return 1;
}
struct Point
{
    double x,y;
    Point(){}
    Point(double _x,double _y)
    { x = _x;y = _y;
    }
    Point operator -(const Point &b)const
    {
        return Point(x - b.x,y - b.y);
    }
//叉积
    double operator ^(const Point &b)const
    {
        return x*b.y - y*b.x; }
//点积
    double operator *(const Point &b)const
    {
        return x*b.x + y*b.y; }
//绕原点旋转角度B(弧度值),后x,y的变化
    void transXY(double B)
    {
        double tx = x,ty = y; x = tx*cos(B) - ty*sin(B);
        y = tx*sin(B) + ty*cos(B);
    }
};
struct Line
{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e)
    { s = _s;e = _e;
    }
    pair<int,Point> operator &(const Line &b)const
    {
        Point res = s;
        if(sgn((s-e)^(b.s-b.e)) == 0)
        {
            if(sgn((s-b.e)^(b.s-b.e)) == 0)
                return make_pair(0,res);//重合
            else return make_pair(1,res);//平行
        }
        double t = ((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
        res.x += (e.x-s.x)*t;
        res.y += (e.y-s.y)*t;
        return make_pair(2,res);
    }
};
Point PointToLine(Point P,Line L)
{
    Point result;
    double t = ((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));
    result.x = L.s.x + (L.e.x-L.s.x)*t;
    result.y = L.s.y + (L.e.y-L.s.y)*t;
    return result;
}
double dist(Point a,Point b)
{
    return sqrt((a-b)*(a-b));
}
int dist2(Point a,Point b)
{
    return (a-b)*(a-b);
}
Point lis[maxn];
int Stack[maxn],top;
//相对于list[0]的极角排序

bool _cmp(Point p1,Point p2)
{
    if( !sgn( p1.x-p2.x ) ) return p1.y < p2.y;
    return p1.x < p2.x;
}
void Graham(int n)
{
    sort(lis,lis+n,_cmp);
    top = 0;
    for(int i = 0;i < n;i++)
    {
        while(top > 1 &&sgn((lis[Stack[top-1]]-lis[Stack[top-2]])^(lis[i]-lis[Stack[top-2]])) <=0)
            top--;
        Stack[top++] = i;
    }
    int k = top;
    for( int i = n-2;i >= 0;i-- ){
        while( top > k && sgn((lis[Stack[top-1]]-lis[Stack[top-2]])^(lis[i]-lis[Stack[top-2]])) <=0 ){
            top--;
        }
        Stack[ top++ ] = i;
    }
    top--;
}
lint ans1[maxn][maxn],ans2[maxn][maxn],flag1[maxn][maxn],flag2[maxn][maxn];
void rotating_calipers(Point p[],int n)
{
    Point v;
    for( int i = 0;i < n;i++ ){
        lint cur = (i+2)%n;
        lint cur2 = i;
        for( int j = i+2; j < n ;j++ ){
            if( i == 0 && j == n-1 ) break;
            while( ((p[i] - p[j])^( p[(cur+1)%n] - p[cur] )) < 0 ) cur = (cur+1)%n;
            while( ((p[i] - p[j])^( p[(cur2+1)%n]-p[cur2] )) > 0 ) cur2 = (cur2+1)%n;
            ans1[i][j] = cur;flag1[i][j] = 1;
            ans2[i][j] = cur2;flag2[i][j] = 1;
        }
    }
    return;
}
Point p[maxn];
int main(){
    lint n;
    double x,y;
    lint tot = 0;
    scanf("%d",&n);
    for( lint i = 1;i <= n;i++ ){
        scanf("%lf%lf",&x,&y);
        lis[tot++] = Point( x,y );
    }
    Graham(n);
    for( lint i = 0;i < top;i++ ){
        p[i] = lis[Stack[i]];
    }
    rotating_calipers( p,top );
    double ans  = 0;
    for( lint i = 0;i < top;i++ ){
        for( lint j = 0;j < top;j++ ){
            if( flag1[i][j]&&flag2[i][j] ){
                Point x = p[i] - p[j];
                Point y1 = p[ans1[i][j]] - p[j];
                Point y2= p[ ans2[i][j] ] - p[j];
                ans = max( ans,(abs((x^y1)) + abs((x^y2)))/2 );
            }
        }
    }
    printf("%.3lf\n",ans);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值