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

链接:

#include 
int main()
{
    puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/46608743");
}

题解:

对于一个点对,如果它的连线的方程的 x 为定值 ,即为一条竖线,那么我可以把所有点以 x 为第一键值, y 为第二键值排序,然后这条线两端的第一个点与这条线段做个三角形,其面积都可能更新答案。。

然后我们可以先把所有线按照斜率排个序,然后发现每次按序修改y轴,可以 O(1) 得到旋转坐标系后的点的序列。
可以观察此图(这是个小特例福利哦):
【BZOJ3707】圈地 计算几何 旋转坐标系_第1张图片
呃。就是每次旋转到一条斜率时,旋转前是是斜的 (A>B),旋转完就变成了竖着的 (B>A) ,此时只要简单交换一下 AB 在序列中位置就好了~如下图:
【BZOJ3707】圈地 计算几何 旋转坐标系_第2张图片

代码:

(我才不会告诉你们虽然AC,但是实测时感觉貌似哪里挂了呢QwQ)

#include 
#include 
#include 
#include 
#include 
#define N 1010
#define INF 1e60
#define Area(A,B,C) abs(xmul(A,B)+xmul(B,C)+xmul(C,A))
using namespace std;
struct Point
{
    double x,y;
    void read(){scanf("%lf%lf",&x,&y);}
    bool operator < (const Point &A)const{return xint id[N],cr[N];
struct Line
{
    int u,v; // 点标号……
    double k;
    void keep(int _u,int _v)
    {u=_u,v=_v,k=(p[u].y-p[v].y)/(p[u].x-p[v].x);}
    bool operator < (const Line &A)const{return kinline double xmul(Point B,Point C,Point A=Zero)
{return (C.y-A.y)*(B.x-A.x)-(B.y-A.y)*(C.x-A.x);}

int n,m;
double ans=INF;

void work(int u,int v)
{
    if(id[u]>id[v])swap(u,v);
    if(id[u]>1)ans=min(ans,Area(p[u],p[v],p[cr[id[u]-1]]));
    if(id[v]1]]));
    swap(id[u],id[v]),cr[id[u]]=u,cr[id[v]]=v;
}

int main()
{
//  freopen("test.in","r",stdin);

    int i,j;

    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        p[i].read();
        id[i]=cr[i]=i;
    }
    sort(p+1,p+n+1);
    for(i=1;i<=n;i++)for(j=i+1;j<=n;j++)
        l[++m].keep(i,j);
    sort(l+1,l+m+1);
    for(i=1;i<=m;i++)work(l[i].u,l[i].v);
    printf("%.2lf\n",ans/2.0);

    return 0;
}

你可能感兴趣的:(计算几何,旋转坐标系)