关闭

POJ1113(Wall) && Hdu1392(Surround the Trees) (计算几何--凸包)

标签: 计算几何凸包
172人阅读 评论(0) 收藏 举报
分类:
Wall
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 31844   Accepted: 10756

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 a beautiful brick wall with a perfect shape and nice tall towers. Instead, he ordered to build the wall around the whole castle using the least amount of stone and labor, but demanded that the wall should not come closer to the castle than a certain distance. If the King finds that the Architect has used more resources to build the wall than it was absolutely necessary to satisfy those requirements, then the Architect will loose his head. Moreover, he demanded Architect to introduce at once a plan of the wall listing the exact amount of resources that are needed to build the wall.

Your task is to help poor Architect to save his head, by writing a program that will find the minimum possible length of the wall that he could build around the castle to satisfy King's requirements.

The task is somewhat simplified by the fact, that the King's castle has a polygonal shape and is situated on a flat ground. The Architect has already established a Cartesian coordinate system and has precisely measured the coordinates of all castle's vertices in feet.

Input

The first line of the input file contains two integer numbers N and L separated by a space. N (3 <= N <= 1000) is the number of vertices in the King's castle, and L (1 <= L <= 1000) is the minimal number of feet that King allows for the wall to come close to the castle. 

Next N lines describe coordinates of castle's vertices in a clockwise order. Each line contains two integer numbers Xi and Yi separated by a space (-10000 <= Xi, Yi <= 10000) that represent the coordinates of ith vertex. All vertices are different and the sides of the castle do not intersect anywhere except for vertices.

Output

Write to the output file the single number that represents the minimal possible length of the wall in feet that could be built around the castle to satisfy King's requirements. You must present the integer number of feet to the King, because the floating numbers are not invented yet. However, you must round the result in such a way, that it is accurate to 8 inches (1 foot is equal to 12 inches), since the King will not tolerate larger error in the estimates.

Sample Input

9 100
200 400
300 400
300 300
400 300
400 400
500 400
500 200
350 200
200 200

Sample Output

1628

凸包:

(1)问题:

给定二维平面点集,求最小的包含所有点的凸多边形。

(2)Gramham-Scan算法:

Gramham-Scan是一种灵活的凸包算法,其总的时间复杂度仅为O(n*log(n))。

步骤:

Step1: 选定x坐标最小(相同情况y最小)的点作为极点,这个点必在凸包上;

Step2: 将其余点按极角排序,在极角相同的情况下比较与极点的距离,离极点比较近的优先;

Step3: 用一个栈S存储凸包上的点,先将按极角和极点排序最小的两个点入栈;

Step4: 按序扫描每个点,检查栈顶的两个元素与这个点构成的折线段是否“拐”向右侧(叉积小于等于零);

Step5: 如果满足,则弹出栈顶元素,并返回Step4再次检查,直至不满足。将该点入栈,并对其余点不断执行此操作;

Step6: 最终栈中元素为凸包的顶点序列。





解题思路:

这道题的答案是凸包周长加上一个圆周长,即包围凸包的一个圆角多边形,但是没弄明白那些圆角加起来为什么恰好是一个圆。每个圆角是以凸包对应的顶点为圆心,给定的L为半径,与相邻两条边的切点之间的一段圆弧。每个圆弧的两条半径夹角与对应的凸包的内角互补。假设凸包有n条边,则所有圆弧角之和为180°*n-180°*(n-2)=360°。故,围墙周长为=n条平行于凸包的线段+n条圆弧的长度=凸包周长+围墙离城堡距离L为半径的圆周长.


模版:(来自kuangbin大神)

#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×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++)
        {
            //栈顶和栈顶下面那个元素和当前遍历的元素的叉积,栈顶下面那个元素的下标是最小的,假设p1p2,p1p3,如果p1p2在p1p3的逆时针那么就不满足条件
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--; 
            top++;
            stack[top]=i; //否则插入当前栈顶
        }
    }
}

int main()
{
    int N,L;
    //freopen("111","r",stdin);
    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;
}



Surround the Trees

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8636    Accepted Submission(s): 3326


Problem Description
There are a lot of trees in an area. A peasant wants to buy a rope to surround all these trees. So at first he must know the minimal required length of the rope. However, he does not know how to calculate it. Can you help him?
The diameter and length of the trees are omitted, which means a tree can be seen as a point. The thickness of the rope is also omitted which means a rope can be seen as a line.



There are no more than 100 trees.
 

Input
The input contains one or more data sets. At first line of each input data set is number of trees in this data set, it is followed by series of coordinates of the trees. Each coordinate is a positive integer pair, and each integer is less than 32767. Each pair is separated by blank.

Zero at line for number of trees terminates the input for your program.
 

Output
The minimal length of the rope. The precision should be 10^-2.
 

Sample Input
9 12 7 24 9 30 5 41 9 80 7 50 87 22 9 45 1 50 7 0
 

Sample Output
243.06


本题注意:

n = 1和n = 2的时候要特判不能套凸包模版,还有注意精度问题.

Hdu1392 AC代码:

#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
{
    double x,y;
};
point list[MAXN];
int stack[MAXN],top;

double cross(point p0,point p1,point p2) //计算叉积p0p1×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) //极角排序函数,角度相同则距离小的在前面
{
    double tmp=cross(list[0],p1,p2);
    if(tmp>0.0) return true;
    else if(tmp==0.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("%lf%lf",&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("%lf%lf",&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++)
        {
            //栈顶和栈顶下面那个元素和当前遍历的元素的叉积,栈顶下面那个元素的下标是最小的,假设p1p2,p1p3,如果p1p2在p1p3的逆时针那么就不满足条件
            while(top>0 && cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i; //否则插入当前栈顶
        }
    }
}

int main()
{
    int m;
    //freopen("1.txt","r",stdin);
    while(cin>>m && m)
    {
        init(m);
        graham(m);
        double res=0;
        if(m == 1)
        {
        	printf("0.00\n");
		}
		else if(m == 2)
		{
			printf("%.2lf\n",dis(list[0],list[1]));
		}
		else
		{
	        for(int i=0;i<top;i++)
	          res+=dis(list[stack[i]],list[stack[i+1]]); //加入栈的元素就是凸包上的顶点.
	        res+=dis(list[stack[0]],list[stack[top]]); 
	
	        printf("%.2lf\n",res);
		}
    }
    return 0;
}



0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:60908次
    • 积分:2327
    • 等级:
    • 排名:第16690名
    • 原创:178篇
    • 转载:15篇
    • 译文:0篇
    • 评论:6条
    最新评论