HDU1392 凸包问题求周长 + 裸 + Graham算法

0)

        思路很好理解,但是写的过程中很容易写错!

        ①:sort排序时,其他点相对最左下角的点,先按极角由小到大排序,极角相同,按距离由近到远排序。(会留下最后进栈的,也就是留下距离远的,是对的)

        ②:Graham()里的while条件语句中,points[i]是和已经进栈的sstack[top]、sstack[top-1]比较,而不是points[top]、points[top-1]!

        ③:Graham()里的while条件语句while ((1<top) && (mulity(points[i], sstack[top], sstack[top - 1])>0));  ,之前在后面多加一个 ; 而出现各种奇怪答案 ,不要小看这一个分号,编译器不报错,而且会先认为是一个执行语句并执行,while则不判断就认为是TRUE,执行一遍while里的内容,然后再正常判断while里的条件语句是真是假!!

        

        关于细节:

        ①:如果在Graham()里的while条件语句中出现三点(points[i]、sstack[top]、sstack[top-1])一线的情况时,若写mulity()>0,则top++,points[i]入栈,即三个点都入栈;如果写while()中写mulity()>=0,则三点一线时,top位置的点出栈,即第二个点出栈,最终只保留该直线第一个点和最后一个点。这两种情况最后得出的凸包的周长是相同的,但是凸包上的点是不同的,后者有舍弃,前者没有,所以注意这里可以出变型的题。

        ②:在sort的cmp自定义排序函数中,如果极角相同,应该距离近的在前面是有必要的。考虑当向量方向相同,距离短的在前(假设是B点),长的(假设是C点)在后,这样在Graham里的while循环判断中,如果恰好出现这样的极端情况:最左下角的点(假设是A)位于栈里的top-1的位置,B点位于top,C点位于i,则top--,将点A出栈,将点B进栈,然后计算距离时,这一段是计算点A到点C,正解。如果是距离远的在前,那么应当是点B位于i,点C位于top,那么while判断里因为极角相同则top--,点C出栈,点B进栈,计算这一段距离时,则是A到B,错的。围成的凸包也不对。

         ③:关于叉乘、判断方向以及如何进出“栈”,等等,都在代码中有详细注释,就不再一一赘述。

1)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>

using namespace std;
const int maxn = 110;
struct Point{
	int x;
	int y;
}points[maxn], sstack[maxn];
int top;
int n;
int mulity(Point p1, Point p2, Point p0){//注意,这里直接返回计算结果就行,不要再判断什么情况下返回1什么情况下返回0,因为这是重用度比较高的函数,是位于“底层”的,直接返回结果到上层中判断远比自己加一个判断要好得多!
	return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);//向量p0p1 到 向量p0p2,叉乘大于0,意味着,右手定则右手四指指向p0p1的方向握向p0p2的方向时,大拇指朝外
}
double dis(Point a, Point b){
	return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
bool cmp(Point p1, Point p2){//p0p1 到 p0p2
	//向量方向相同,距离短的在前(假设是B点),长的(假设是C点)在后,这样在Graham里的while循环判断中,如果恰好出现这样的极端情况:最左下角的点(假设是A)位于栈里的top-1的位置,B点位于top,C点位于i,则top--,将点A出栈,将点B进栈,然后计算距离时,这一段是计算点A到点C,正解。如果是距离远的在前,那么应当是点B位于i,点C位于top,那么while判断里因为极角相同则top--,点C出栈,点B进栈,计算这一段距离时,则是A到B,错的。围成的凸包也不对。
	int k = mulity(p1, p2, points[0]);
	if (k>0){
		return 1;
	}
	else if (k == 0 && dis(p1, points[0]) <= dis(p2, points[0])){
		return 1;
	}
	return 0;
}
void Graham(){
	top = -1;
	for (int i = 0; i<n; i++){
        //遇到i,比较i和当前栈顶元素top,谁在外围谁留下,即mulity(p1,p2,p0),右手由p0p1 握向 p0p2,拇指朝里,则叉乘<=0,所以p2靠外所以压栈,而p1在内所以出栈。
		while ((1<top) && (mulity(points[i], sstack[top], sstack[top - 1])>0)){//mulity()>=0也是可以的
		    //while的判断语句,调试了一上午!一个是因为sstack之前用points代替,不和栈里的数做比较明显是错的,但这个地方确实很容易写错,高危!!!;另一个是因为多打了一个分号,则按while判断句按陈述语句先执行,然后因为检测到while里的判断句被执行了,所以while()内的语句一定先执行一次然后才进入下一次while里的条件语句进行判断要不要再进while循环!!
			top--;//若将i与top-1两点相连,则当前top点在内侧。所以当前top点出栈。退回到上一个top点与top-1,继续比较,直到当i入栈时,已入栈的点不会被包裹在内侧。
		}
		//i点可入栈,并且不会破坏当前栈中所有点可构成凸包(即不会出现,连接栈中任意两点使得栈中任意一点会在连线内侧的情况)
		sstack[++top] = points[i];
	}
}
int main()
{
	while (~scanf("%d", &n) && n != 0){

		//输入数据,并且找到左下角的点
		scanf("%d%d", &points[0].x, &points[0].y);
		int ld_id = 0;//left down id
		for (int i = 1; i<n; i++){
			scanf("%d%d", &points[i].x, &points[i].y);
			if (points[ld_id].y>points[i].y){
				ld_id = i;
			}
			else if (points[ld_id].y == points[i].y&&points[ld_id].x>points[i].x){
				ld_id = i;
			}
		}
		if (n == 1){
			printf("%.2f\n", 0.00);
			continue;
		}
		else if (n == 2){
			printf("%.2f\n", dis(points[0], points[1]));
			continue;
		}
		//把左下角的点放到数组第一个
		Point temp = points[0];
		points[0] = points[ld_id];
		points[ld_id] = temp;
		//其他点按照与p0的极角由小到大排序,极角相同按距离由近到远排序,这样在Graham里的循环判断找凸包时,会将先进栈的最近的点踢出去,将距离最远的点留下,这样做所求的这一段距离才是对的,如果最后留下最近的点则形成的凸包漏掉了这个最远的点,所求距离自然也是过短的
		sort(points + 1, points + (n), cmp);
		//for(int i=0;i<n;i++)
            //cout<<points[i].x<<" "<<points[i].y<<endl;
		Graham();
		double res = 0;//凸包周长
		//机智的0到top的相加..
		for (int i = 0; i <= top; i++){
			res += dis(sstack[i], sstack[(i + 1) % (top + 1)]);
		}
		printf("%.2f\n", res);
	}
}
2)

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


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值