POJ 2187 Beauty Contest(凸包优化 || 凸包+旋转卡壳)

大意:求解点和点之间的最大距离的平方。
记得曾经有一道CF的题自己写了一个3重循环也过了,当时自己怀疑计算机一秒是运算10^9吗,还是数据太弱。。。写了一个1e9的程序,果断超时。看来1e8才是保险值

TLE:

#include <iostream>
#include <cstdio>
using namespace std;
const int N=5e4+10;
struct point{
    int x,y;
}p[N];
int dis(point a,point b){
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int main()
{
    int n;
    while(cin>>n){
        int ans=0;
        for(int i=0;i<n;i++){
            scanf("%d%d",&p[i].x,&p[i].y);
        }
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                int temp=dis(p[i],p[j]);
                ans=ans>temp?ans:temp;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

后经分析,此题需要用凸包优化:
我又画个图说明:

我们总能在凸包上寻找另一个点使得凸包上一对点的距离大于图中灰色线段的长。换句话说,题目中要求的距离(的平方)就在凸包上。
(time: 157ms  memory: 632k          嘿嘿,效果还行)

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=5e4+10;
struct point{
    int x,y;
}p[N];
int dis(point a,point b){
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int cross(point p0,point p1,point p2){
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int cmp1(point p1,point p2){
    return p1.x<p2.x||(p1.x==p2.x&&p1.y<p2.y);
}
int cmp2(point p1,point p2){
    int c=cross(p[0],p1,p2);
    if(c==0) return dis(p[0],p1)<dis(p[0],p2);
    return c>0;
}
point ans[N];
int top;
void convex(int n){
    top=0;
    sort(p,p+n,cmp1);
    sort(p+1,p+n,cmp2);
    ans[top++]=p[0];
    ans[top++]=p[1];
    for(int i=2;i<n;i++){
        if(cross(ans[top-2],ans[top-1],p[i])>0) ans[top++]=p[i];
        else {
            top--;
            while(top>=2&&cross(ans[top-2],ans[top-1],p[i])<=0) top--;
            ans[top++]=p[i];
        }
    }
    //ans[top++]=p[0]; //因为本题比较距离的特殊性,所以不用围成凸包
}
int main()
{
    //freopen("cin.txt","r",stdin);
    int n;
    while(cin>>n){
        for(int i=0;i<n;i++){
            scanf("%d%d",&p[i].x,&p[i].y);
        }
        convex(n);
        int res=0;
        for(int i=0;i<top;i++){
            for(int j=i+1;j<top;j++){
                int temp=dis(ans[i],ans[j]);
                res=res>temp?res:temp;
            }
        }
        printf("%d\n",res);
    }
    return 0;
}

后来听说,这题涉及到旋转卡壳和 最远点对。啊,原来还有其他做法。先到这里,继续学习。。。

========================================================================

2016.01.23

学习了旋转卡壳,现在用旋转卡壳来做它:

旋转卡壳用于凸包已经求得基础上寻找一对点的最大距离(当然他还有其他作用)。
凸多边形直径定理:凸多边形P的直径等于P的所有平行支撑线之间距离的最大值。
旋转卡壳的算法展示图片:

(我打不开上面这个链接。。。)
这篇博文的算法实现是比较好的: http://www.cppblog.com/staryjy/archive/2009/11/19/101412.html
相关代码:
int rotating()
{
    int q=1,ans=0;
    sta[top]=sta[0];
    for(int i=0;i<top;i++)
    {
        while(cross(sta[i],sta[i+1],sta[q+1])>cross(sta[i],sta[i+1],sta[q]))
            q=(q+1)%top;
        ans=max(ans,max(dis(sta[i],sta[q]),dis(sta[i+1],sta[q+1])));
       // ans=max(ans,max(dis(sta[i],sta[q]),dis(sta[i+1],sta[q])));
    }
    return ans;
}

while循环不断更新对象点,直到对象点是离现有线段(边)最远的点。此时更新最大距离ans。其中  ans=max(ans,max(dis(sta[i],sta[q]),dis(sta[i+1],sta[q+1]))); 的解释: 主要考虑到平行线的情况。

POJ 2187 居然用下面那条注释的语句也过了,这应该是数据弱了。。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=5e4+10;
struct point{
    int x,y;
}p[N];
int dis(point a,point b){
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int cross(point p0,point p1,point p2){
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int cmp1(point p1,point p2){
    return p1.x<p2.x||(p1.x==p2.x&&p1.y<p2.y);
}
int cmp2(point p1,point p2){
    int c=cross(p[0],p1,p2);
    if(c==0) return dis(p[0],p1)<dis(p[0],p2);
    return c>0;
}
point sta[N];
int top;
void convex(int n){
    top=0;
    sort(p,p+n,cmp1);
    sort(p+1,p+n,cmp2);
    sta[top++]=p[0];
    sta[top++]=p[1];
    for(int i=2;i<n;i++){
        if(cross(sta[top-2],sta[top-1],p[i])>0) sta[top++]=p[i];
        else {
            top--;
            while(top>=2&&cross(sta[top-2],sta[top-1],p[i])<=0) top--;
            sta[top++]=p[i];
        }
    }
}

int rotating()
{
    int q=1,ans=0;
    sta[top]=sta[0];
    for(int i=0;i<top;i++)
    {
        while(cross(sta[i],sta[i+1],sta[q+1])>cross(sta[i],sta[i+1],sta[q]))
            q=(q+1)%top;
        ans=max(ans,max(dis(sta[i],sta[q]),dis(sta[i+1],sta[q+1])));
    }
    return ans;
}

int main()
{
    //freopen("cin.txt","r",stdin);
    int n;
    while(cin>>n){
        for(int i=0;i<n;i++){
            scanf("%d%d",&p[i].x,&p[i].y);
        }
        convex(n);
        printf("%d\n",rotating());
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值