zoukankan      html  css  js  c++  java
  • 【HDOJ】1348 Wall【计算几何-凸包】

    临近区域赛,想要系统地过一下知识点,发现了一个好网站,推荐一波。
    HDOJ 根据题目类型做的分类(杭电牛逼)

    第一次做凸包题

    题意就是求凸包构成的多边形周长+一个圆的周长

    凸包的概念

    在二维欧几里得空间中,凸包可想象为一条刚好包着所有点的橡皮圈。

    求凸包的方法

    《算导》给了两种方法

    1. Graham扫描法
    2. Jarvis步近法
      详见《算导》

    我这边用的是《算法竞赛入门经典-训练指南》里的模板,基于水平序的Andrew算法(是 Graham扫描法的变种,更快且数值稳定性更好)。

    int ConvexHull(Point *p,int n,Point *ch)
    {
    	sort(p,p+n);//先比较x坐标,再比较y坐标
    	int m=0;
    	for(int i=0;i<n;i++)
    	{
    		while(m>1 && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
    		ch[m++]=p[i];
    	}
    	int k=m;
    	for(int i=n-2;i>=0;i--)
    	{
    		while(m>k && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
    		ch[m++]=p[i];
    	}
    	if(n>1)
    		m--;
    	return m;
    }
    

    实在是太菜了,感觉对的啊,又没能AC

    My Wrong Code And Online AC Code

    /*
    核心:求凸包
    */
    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1005;
    
    struct Point
    {
    	double x,y;
    	//构造函数
    	Point(double x=0,double y=0 ):x(x),y(y){}
    
    };
    
    typedef Point Vector;// 别名
    const double eps=1e-10;
    
    Vector operator + (Vector A,Vector B)
    {
    	return Vector(A.x+B.x,A.y+B.y);
    }
    
    Vector operator - (Point A,Point B)
    {
    	return Vector(A.x-B.x,A.y-B.y);
    }
    
    Vector operator * (Point A,double p)
    {
    	return Vector(A.x*p,A.y*p);
    }
    
    Vector operator / (Point A,double p)
    {
    	return Vector(A.x/p,A.y/p);
    }
    
    bool operator <(const Point&a,const Point &b)
    {
    	return a.x<b.x||(a.x==b.x&&a.y<b.y);
    }
    
    //向量判断符号
    int dcmp(double x)
    {
    	if(fabs(x)<eps)
    		return 0;
    	else
    		return x<0?-1:1;
    }
    
    
    bool operator ==(const Point&a,const Point &b)
    {
    	return dcmp(a.x-b.x)==0 &&dcmp(a.y-b.y)==0;
    }
    
    //点积
    double Dot(Vector A,Vector B)
    {
    	return A.x*B.x+A.y*B.y;
    }
    
    // 叉积
    double Cross(Vector A,Vector B)
    {
    	return A.x*B.y-A.y*B.x;
    }
    
    // 判断线段相交,忽略两端点
    bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)
    {
    	double c1=Cross(a2-a1,b1-a1), c2=Cross(a2-a1,b2-a1),
    		   c3=Cross(b2-b1,a1-b1), c4=Cross(b2-b1,a2-b1);
    	return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
    }
    
    // 点是否在线段上
    bool OnSegment(Point p,Point a1,Point a2)
    {
    	return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
    }
    
    int ConvexHull(Point *p,int n,Point *ch)
    {
    	sort(p,p+n);//先比较x坐标,再比较y坐标
    	int m=0;
    	for(int i=0;i<n;i++)
    	{
    		while(m>1 && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
    		ch[m++]=p[i];
    	}
    	int k=m;
    	for(int i=n-2;i>=0;i--)
    	{
    		while(m>k && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
    		ch[m++]=p[i];
    	}
    	if(n>1)
    		m--;
    	return m;
    }
    double distance (Point a,Point b)
    {
    	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    
    Point p[maxn],ch[maxn];
    
    int main()
    {
    	int t;
    	scanf("%d",&t);
    	while(t--)
    	{
    		int n,l;
    		scanf("%d%d",&n,&l);
    		for(int i=0;i<n;i++)
    		{
    			scanf("%lf%lf",&p[i].x,&p[i].y);
    		}
    		int hlength=ConvexHull(p,n,ch);
    		double res=0;
    		
    		for(int i=1;i<hlength;i++)
    		{
    			res+=distance(ch[i],ch[i-1]);
    		}
    		res+=distance(ch[0],ch[hlength-1]);
    		res+=2*3.14*l;
    		printf("%d
    ",(int)res);
    		if (t) cout << endl;
    	}
    	
        return 0;
    }
    
    /*
    //又是网上别人AC的代码
    //我为什么这么菜
    //参考 https://blog.csdn.net/yuanxu716/article/details/73433752
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cmath>
    using namespace std;
     
    const int MAXN = 1005;
    const double PI = acos(-1.0);
    const double EPS = 1E-6;
     
    int T, N, L;
     
    struct Point{
    	int x;
    	int y;
    } p[MAXN];
    vector<Point> vec;
     
    double dist(Point a, Point b) {
    	return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
    }
     
    double crossProduct(Point a, Point b, Point c) { // ab * ac
    	return (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x) - 0.0;
    }
     
    bool cmp(Point a, Point b) {
    	double cp = crossProduct(p[0], a, b);
    	if (cp > EPS) return true;
    	else if (cp < -EPS) return false;
    	else return dist(p[0], a) < dist(p[0], b);
    }
     
    int findLf(Point p[]) {		// find lowest leftest point/vertice.
    	int index = 0;
    	for (int i = 1; i < N; i++) {
    		if (p[i].y < p[index].y) index = i;
    		else if (p[i].y == p[index].y && p[i].x < p[index].x) index = i;
    	}
    	return index;
    }
     
    void graham(Point p[]) {    // graham algorithm for convex hall.
    	vec.clear();
    	vec.push_back(p[0]); vec.push_back(p[1]);
    	int top = 1;
    	for (int i = 2; i < N; i++) {   // another way: i <= N, and comment the line below:ans += dist(vec[vec.size() - 1], vec[0]);
    		while (top >= 1 && crossProduct(vec[top - 1], vec[top], p[i]) <= 0) {
    			vec.pop_back();
    			top--;
    		}
    		vec.push_back(p[i]);
    		top++;
    	}
    }
     
     
    int main() {
    	cin >> T;
    	while (T--) {
    		cin >> N >> L;
    		for (int i = 0; i < N; ++i) {
    			cin >> p[i].x >> p[i].y;
    		}
    		int lf = findLf(p);
    		swap(p[0], p[lf]);
    		p[N] = p[0];
    		sort(p + 1, p + N, cmp);
    		graham(p);
     
    		double ans = 0.0;
    		for (int i = 1; i < (int)vec.size(); i++) {
    			ans += dist(vec[i - 1], vec[i]);
    		}
    		ans += dist(vec[vec.size() - 1], vec[0]);
    		ans += 2 * PI * L;
    		cout << (int)round(ans) << endl;
    		if (T) cout << endl;
    	}
    	return 0;
    }
    
    */
    
  • 相关阅读:
    java输出菱型
    java----内部类
    java中的多重继承
    java算法--三个数字比较大小
    Python基础(2)
    Python基础(1)
    Redis主从同步
    一种高效的进程间的通信方式
    自旋锁和互斥锁的区别
    Linux读写锁的使用
  • 原文地址:https://www.cnblogs.com/shengwang/p/9767374.html
Copyright © 2011-2022 走看看