POJ - 1113 Wall (凸包)

http://poj.org/problem?id=1113

题意

求能包围城堡的最小周长,其中必须与城堡每个点相隔L。

分析

答案是凸包周长加上一个圆周长,即包围凸包的一个圆角多边形。

但那些圆角加起来为什么恰好是一个圆呢?每个圆角是以凸包对应的顶点为圆心,给定的L为半径,与相邻两条边的切点之间的一段圆弧。

每个圆弧的两条半径夹角与对应的凸包的内角互补。假设凸包有n条边,则所有圆弧角之和为180°*n-180°*(n-2)=360°。(凸边形内角和为(n-2)*180)

故,围墙周长为=n条平行于凸包的线段+n条圆弧的长度=凸包周长+围墙离城堡距离L为半径的圆周长。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int MAXN=1000;
const double PI=acos(-1.0);

struct point
{
    int x,y;
};
point list[MAXN];
int stack[MAXN],top;

int cross(point p0,point p1,point p2) //计算叉积  p0p1 X p0p2
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //计算 p1p2的 距离
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //极角排序函数 , 角度相同则距离小的在前面
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //输入,并把  最左下方的点放在 list[0]  。并且进行极角排序
{
    int i,k;
    point p0;
    scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}     

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}    

int main()
{
    int N,L;
    while(scanf("%d%d",&N,&L)!=EOF)
    {
        init(N);
        graham(N);
        double res=0;
        for(int i=0;i<top;i++)
          res+=dis(list[stack[i]],list[stack[i+1]]);
        res+=dis(list[stack[0]],list[stack[top]]);

        res+=2*PI*L;
        printf("%d\n",(int)(res+0.5));

    }
    return 0;
}

原文地址:https://www.cnblogs.com/fht-litost/p/9350133.html

时间: 2024-08-26 06:10:24

POJ - 1113 Wall (凸包)的相关文章

poj 1113 Wall (凸包模板题)

Wall Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 32808   Accepted: 11137 Description Once upon a time there was a greedy King who ordered his chief Architect to build a wall around the King's castle. The King was so greedy, that he w

POJ 1113 Wall (凸包)

题目地址:POJ 1113 先求出凸包的周长,然后剩下的弧合起来一定是个半径为l的圆,然后再加上以l为半径的圆的周长即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <

poj 1113 Wall 凸包的应用

题目链接:poj 1113   单调链凸包小结 题解:本题用到的依然是凸包来求,最短的周长,只是多加了一个圆的长度而已,套用模板,就能搞定: AC代码: 1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cmath> 5 using namespace std; 6 int m,n; 7 struct p 8 { 9 double x,y; 10 friend i

POJ 1113 Wall 凸包 裸

LINK 题意:给出一个简单几何,问与其边距离长为L的几何图形的周长. 思路:求一个几何图形的最小外接几何,就是求凸包,距离为L相当于再多增加上一个圆的周长(因为只有四个角).看了黑书使用graham算法极角序求凸包会有点小问题,最好用水平序比较好.或者用Melkman算法 /** @Date : 2017-07-13 14:17:05 * @FileName: POJ 1113 极角序求凸包 基础凸包.cpp * @Platform: Windows * @Author : Lweleth (

POJ 1113 - Wall 凸包模板

此题为凸包问题模板题,题目中所给点均为整点,考虑到数据范围问题求norm()时先转换成double了,把norm()那句改成<vector>压栈即可求得凸包. 初次提交被坑得很惨,在GDB中可以完美运行A掉,到OJ上就频频RE(此处应有黑人问号) 后来发现了问题,原因是玩杂耍写了这样的代码 struct point { int x, y; point (){ scanf("%d%d", &x, &y); } ... }pt[MAXN]; 于是乎,在swap

POJ - 1113 Wall (凸包模板题)

原题链接 模板题,直接说思路. 思路: 要求一距离凸包为 L 的图形的周长,即为 凸包周长+L为半径的圆周长 ,直接用 Graham 求一次凸包即可. 1 /* 2 * @Author: windystreet 3 * @Date: 2018-08-02 20:41:25 4 * @Last Modified by: windystreet 5 * @Last Modified time: 2018-08-02 22:30:59 6 */ 7 #include <stdio.h> 8 #inc

POJ 1113 Wall (凸包 + 思维)

题目:传送门 题意:有一个 n 多边形城堡,先需在城堡外建围墙,使得围墙到城堡的距离不得小于 L,且围墙的周长最小. 思路:答案就是凸包周长 + 半径为 L 的圆的周长.   证明 A.B.C.D四个点,每个点都有 360 度, 然后,角1.2.3.4构成多变形的内角和为 360度,然后每个点,又要减去两个90度,那么剩下的就是圆心角5.6.7.8,它们的和为 4 * (360 - 180) - 360 = 360,刚好是一个圆.推广到任意多边形也是类似的. #include <iostream

G++和C++ &amp;&amp; POJ 1113 Wall

PS: 次题目虽然叙述点的个数大于等于3但是并不保证凸包是否存在,所以还要判断一下.经常刷题的孩纸可能会遇到用C++ 可用AC的题目用G++ 却 Wrong Answer. 思考过为什么吗? 对于double 类型用%lf 输入用%lf输出是window 环境下VC的标准但不是真正的标准,对于double 类型 真正的标准是用%lf输入,用%f输出.所以把%.0lf改为%.0f 在G++环境下面就可用轻松AC了. 还有%lld 和 %I64d, 同时也学习一下控制精度的技巧,比如 printf(

poj 1113 Wall(标准的凸包果题)

题目链接:http://poj.org/problem?id=1113 Description Once upon a time there was a greedy King who ordered his chief Architect to build a wall around the King's castle. The King was so greedy, that he would not listen to his Architect's proposals to build