BZOJ 3707: 圈地 计算几何

Description

2维平面上有n个木桩,黄学长有一次圈地的机会并得到圈到的土地,为了体现他的高风亮节,他要使他圈到的土地面积尽量小。圈地需要圈一个至少3个点的多边形,多边形的顶点就是一个木桩,圈得的土地就是这个多边形内部的土地。(因为黄学长非常的神,所以他允许圈出的第n点共线,那样面积算0)

Input

第一行一个整数n,表示木桩个数。
接下来n行,每行2个整数表示一个木桩的坐标,坐标两两不同。

题解:

简单的说就是给定平面上n个点,求这n个点组成三角形的最小面积。

如果分别枚举三个点的话是`O(n^3)`的,时间无法承受。

如果枚举了两个点a,b。设它们间的距离是L。如果以点a,b所在直线为y轴的话,与其他点所组成的三角形的面积`S=L*|x|/2`,x是其他点在这个坐标系中的横坐标。可以看出面积最小的就是离这个坐标系y轴最近的一个点。如果我们能够快速的得知最近的点的话,就可以将复杂度降低到`O(n^2)`。

把这些点两两之间求出一条直线,记录这条直线是哪两个点取到的,记录这条直线的斜率k。然后按照k排序,我们可以依次按照k递增连续变化的顺序处理这些直线。

首先将这些点按x坐标排序,相当于按x=0直线排序的情况,考虑由两个相邻的斜率k1变到k2时,这个序列的改变只有k1直线的两个点的顺序交换了下,其它点之间的顺序都没变。在枚举直线时,交换两点维护序列即可。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
//by zrt
//problem:
using namespace std;
typedef long long LL;
const int inf(0x3f3f3f3f);
const double eps(1e-9);
struct point{
    int x,y;
    friend bool operator < (point x,point y){
        return x.x<y.x;
    }
}p[1005];
struct line{
    int x,y;double k;
    friend bool operator < (line a,line b){
        return a.k<b.k;
    }
}l[500005];
int pos[1005],rank[1005];
int n,c;
double ans;
point operator -(point a,point b){
    static point ret;
    ret.x=a.x-b.x;
    ret.y=a.y-b.y;
    return ret;
}
double cross(point a,point b){
    return a.x*1.0*b.y-b.x*1.0*a.y;
}
int main(){
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    ans=1e200;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&p[i].x,&p[i].y);
    }
    sort(p+1,p+1+n);
    for(int i=1;i<=n;i++) rank[i]=pos[i]=i;
    for(int i=1;i<n;i++){
        for(int j=i+1;j<=n;j++){
            l[++c].x=i;l[c].y=j;
            l[c].k=(p[j].y-p[i].y)/(double)(p[j].x-p[i].x);
        }
    }
    sort(l+1,l+c+1);
    int a,b;
    for(int i=1;i<=c;i++){
        a=l[i].x;b=l[i].y;
        if(pos[a]>pos[b]) swap(a,b);
        if(pos[a]>1)ans=min(ans,fabs(cross(p[a]-p[b],p[rank[pos[a]-1]]-p[b])));
        if(pos[b]<n)ans=min(ans,fabs(cross(p[a]-p[b],p[rank[pos[b]+1]]-p[b])));
        swap(pos[a],pos[b]);
        swap(rank[pos[a]],rank[pos[b]]);
    }
    printf("%.2f\n",ans/2.0);
    return 0;
}
时间: 2024-11-10 16:06:39

BZOJ 3707: 圈地 计算几何的相关文章

BZOJ 2132 圈地计划(最小割)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2132 题意:n*m的格子染色黑白,对于格子(i,j)染黑色则价值为A[i][j],白色为B[i][j].若一个格子四周不同颜色的有x个,则额外的价值为x*C[i][j].求最大价值. 思路:将格子黑白染色分成两个集合X和Y.S集合为X中的A和Y中的B,T为X中的B和Y中的A.相邻的连边为两个格子的C值之和.总权值减去最小割即是答案. struct node { int v,cap,ne

BZOJ 1027 JSOI2007 合金 计算几何+Floyd

题目大意:给定一些合金,选择最少的合金,使这些合金能够按比例合成要求的合金 首先这题的想法特别奇异 看这题干怎么会想到计算几何 并且计算几何又怎么会跟Floyd挂边 好强大 首先因为a+b+c=1 所以我们仅仅要得到a和b就可以 c=1-a-b 所以c能够不读入了 然后我们把每种原料抽象成一个点 可知两个点能合成的合金一定在两点连线的线段上 证明:设两个点为(x1,y1)和(x2,y2),新合成的合金为(ax1+bx2,ay2+by2) (a+b=1,a,b>0) 两点连线为(y-y1)/(x-

BZOJ 3232: 圈地游戏 分数规划+判负环

3232: 圈地游戏 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 966  Solved: 466[Submit][Status][Discuss] Description DZY家的后院有一块地,由N行M列的方格组成,格子内种的菜有一定的价值,并且每一条单位长度的格线有一定的费用. DZY喜欢在地里散步.他总是从任意一个格点出发,沿着格线行走直到回到出发点,且在行走途中不允许与已走过的路线有任何相交或触碰(出发点除外).记这条封闭路线内部的格

【BZOJ3707】圈地 计算几何 旋转坐标系

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46608743"); } 题解: 对于一个点对,如果它的连线的方程的 x 为定值 ,即为一条竖线,那么我可以把所有点以 x 为第一键值, y 为第二键值排序,然后这条线两端的第一个点与这条线段做个三角形,其面积都可能更

bzoj 2132: 圈地计划

1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define M 100009 5 #define inf 2139062143 6 using namespace std; 7 int n,m,a[102][102],b[102][102],c[102][102],tot,cnt=1,T,ans,head[M],d[M],q[2*M],next[10*M],u[10*M],v[10*M];

BZOJ 2132 圈地计划 最小割

题目大意:给定一个m*n的矩阵,每个位置如果作为商业区或者工业区各有一个收益,如果相邻两块是不同的也会有一个收益,求最大收益 吐槽:住宅区呢- - 地理老师骗我们- - 普通的最小割建图会遇到一个问题: 割断两块之间的边收益为正,即代价为负 因此我们如果正常建最小割,那么两块之间的边权就会是负的 那么我们将这个矩阵黑白染色,将白格ST反向 这样割断两块之间的连边相当于两块选择了同一用途,代价为正 就可以正常跑了 #include <cstdio> #include <cstring>

BZOJ 1132 POI2008 Tro 计算几何

题目大意:给定平面上的一些点,求这些点能组成的所有三角形的面积之和 首先我们枚举每一个点 以这个点为原点建立平面直角坐标系 然后将第一.四象限和x.y轴正半轴上的点按照斜率排序 枚举第二个和第三个点 这样做是O(n^3)的 肯定超时 但是我们发现了什么? 对于每个点k 它对答案的贡献为: (x1*yk-y1*xk)+(x2*yk-y2*xk)+...+(x_(k-1)*yk-y_(k-1)*xk) =(x1+x2+...+x_(k-1))*yk-(y1+y2+...+y_(k-1))*xk 于是

BZOJ 1094 ZJOI2007 粒子运动 计算几何

题目大意:给定一个圆,一堆粒子在里面反射,每个粒子只能撞墙k次,求全程粒子间距离的最小值 每两个粒子之间计算一遍 反射就是把射线沿着切线作镜像变换 随便搞搞咯-- #include <cmath> #include <cstdio> #include <cstring> #include <iomanip> #include <iostream> #include <algorithm> #define M 110 #define E

bzoj 3232 圈地游戏——0/1分数规划(或网络流)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3232 当然是0/1分数规划.但加的东西和减的东西不在一起,怎么办? 考虑把它们合在一起.因为边围成的形状像一个环,所以把格子的贡献也放到边上,然后正常判环. 放到边上的方法就是:比如竖着的边,可以在每一行上维护该行格子值前缀和,然后指定那个围成的形状是,比如,逆时针的,那么向上的边就加上到它为止的前缀值,向下的边就减去到它为止的前缀值,然后就能判环了! 这样一定只有一个环.但多个环答案不会