您的位置:首页 > 其它

POJ 1113 凸包模板题

2015-05-19 21:16 375 查看
题意:给出一堆城堡(点),问用围墙围起来所有的城堡,令围墙的周长最短(围墙由部分弧形和部分线段组成),围墙距离城堡的距离至少为L

思路:开始直接当成凸包模板题来做了,没想问什么是凸包。先说下凸包的定义,在二维平面下,凸包可以想象成一个围绕着所有点的橡皮圈,任意两个点的连线都包括在这个凸包内。弧形的长度可以证明是一个圆的周长(很好证明),于是周长最短就是围起来所有点的周长最短,这大概就是凸包?暂时先这样。。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<list>
using namespace std;
const double INF = 1e200;
const double EP = 1e-10;
const int maxn = 1100;
const double PI = acos(-1);
struct POINT{///点 定义
double x;
double y;
POINT(double a = 0,double b = 0){x = a;y = b;}
};
struct SEGMENT{///line segment///线段 定义
POINT s;
POINT e;
SEGMENT(POINT a,POINT b){s = a;e = b;}
SEGMENT(){}
};
struct LINE{///ax + by + c = 0&&a >= 0///一般式
double a;
double b;
double c;
LINE(double da,double db,double dc){a = da;b = db;c = dc;}
LINE(double x1,double y1,double x2,double y2){///根据两个点求出一般式
a = y1 - y2;b = x2 - x1;c = x1*y2 - x2*y1;
if(a < 0){a*=-1;b*=-1;c*=-1;}
}
};
double multiply(POINT sp,POINT ep,POINT op){///向量op->sp X op->ep的叉乘,小于0:ep在op->sp顺时针方向//大于0:0:ep在op->sp逆时针方向//等于0:三点共线
return ((sp.x - op.x)*(ep.y - op.y) - (ep.x - op.x)*(sp.y - op.y));
}
double dotmultiply(POINT p1,POINT p2,POINT p0){
return ((p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y));
}
bool online(SEGMENT l,POINT p){///判断点是否在线段上
return ((multiply(l.e,p,l.s) == 0)&&(((p.x-l.s.x)*(p.x-l.e.x))<= 0)&&(((p.y-l.s.y)*(p.y-l.e.y)) <= 0));
}
bool intersect(SEGMENT u,SEGMENT v){///两线段相交(包括端点),返回true
return ((max(u.s.x,u.e.x) >= min(v.s.x,v.e.x))&&
(max(v.s.x,v.e.x) >= min(u.s.x,u.e.x))&&
(max(u.s.y,u.e.y) >= min(v.s.y,v.e.y))&&
(max(v.s.y,v.e.y) >= min(u.s.y,u.e.y))&&
(multiply(v.s,u.e,u.s)*multiply(u.e,v.e,u.s) >= -EP)&&
(multiply(u.s,v.e,v.s)*multiply(v.e,u.e,v.s) >= -EP));
}
bool intersect_a(SEGMENT u,SEGMENT v){///两线段相交(不包括端点)
return ((intersect(u,v))&&
!online(u,v.s)&&
!online(u,v.e)&&
!online(v,u.e)&&
!online(v,u.s));
}
int lineintersect(LINE l1,LINE l2,POINT &p){///求两直线交点,有交点返回1和交点,没有返回0,重合返回2
double d = l1.a*l2.b-l2.a*l1.b;
double d2 = l1.a*l2.c-l2.a*l1.c;
double d3 = l1.b*l2.c-l2.b*l1.c;
if(fabs(d) < EP&&fabs(d2) < EP&&fabs(d3) < EP)return 2;
p.x = (l2.c*l1.b-l1.c*l2.b)/d;
p.y = (l2.a*l1.c-l1.a*l2.c)/d;
if(fabs(d) < EP)return 0;
return 1;
}
double point_dis(POINT a,POINT b){///求两点距离
return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
///****************凸包**************************************

int len_top;///凸包的顶点个数
POINT point_set[maxn],point_stack[maxn];
bool top_cmp(POINT a,POINT b){
if(multiply(a,b,point_set[0]) > 0)return 1;
if(fabs(multiply(a,b,point_set[0])) < EP&&point_dis(a,point_set[0]) < point_dis(b,point_set[0]))return 1;
return 0;
}
void graham_scan(POINT p[],POINT stack[],int n){
len_top = 2;
int k = 0;
for(int i = 1;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[0],p[k]);
sort(p+1,p+n,top_cmp);
stack[0] = p[0],stack[1] = p[1],stack[2] = p[2];
for(int i = 3;i < n;i ++){
while(len_top > 1&&multiply(p[i],stack[len_top],stack[len_top-1]) >= 0)len_top --;
stack[++len_top] = p[i];
}
len_top++;
}
///******************凸包结束****************

///************************************************************************************************************************************

int main(){
//freopen("in.txt","r",stdin);
int n,l;
while(cin>>n>>l){
for(int i = 0;i < n;i ++){
int a,b;
cin>>a>>b;
point_set[i].x = a;
point_set[i].y = b;
}
graham_scan(point_set,point_stack,n);
double ans = 0;
for(int i = 0;i < len_top-1;i ++){
ans += point_dis(point_stack[i],point_stack[i+1]);
}
ans += point_dis(point_stack[len_top-1],point_stack[0]);
ans += (double)l*2*PI;
printf("%d\n",(int)(ans + 0.5));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  凸包