数学板块学习之最小圆覆盖

最小圆覆盖

留下三种方法模板
以一个题为例Buried memory

1.求凸包后枚举凸包上的点。
代码:

 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 
//#include 

using namespace std;
#define me(x,y) memset(x,y,sizeof x)
#define MIN(x,y) x < y ? x : y
#define MAX(x,y) x > y ? x : y
typedef long long ll;
typedef unsigned long long ull;
const double INF = 0x3f3f3f3f;
const double eps = 1e-08;
const double PI = acos(-1.0);
const int mod = 1e9+7;
const int maxn = 1000;

int n;

int sgn(double x){
    if(fabs(x) < eps) return 0;
    if(x < 0)return -1;
    else return 1;
}

inline double sqr(double x){return x*x;}

struct Point{
    double x,y;
    Point(){}
    Point(double _x,double _y){x = _x,y = _y;}
    void input(){scanf("%lf%lf",&x,&y);}
    void output(){printf("%.2f %.2f\n",x,y);}
    bool operator == (Point b) const{return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;}
    bool operator < (Point b) const{return sgn(x-b.x) == 0 ? sgn(y-b.y)<0 : x<b.x;}
    Point operator -(const Point &b)const{return Point(x-b.x,y-b.y);}
    double operator ^ (const Point &b)const{return x*b.y-y*b.x;}    //叉积
    double operator * (const Point &b)const{return x*b.x+y*b.y;}    //点积
    double len(){return hypot(x,y);}                                //返回长度
    double len2(){return x*2+y*y;}                                  //返回长度平方
    double distance(Point p){return hypot(x-p.x,y-p.y);}            //返回两点间距离
    Point operator + (const Point &b)const{return Point(x+b.x,y+b.y);}//
    Point operator * (const double &k)const{return Point(x*k,y*k);} //
    Point operator / (const double &k)const{return Point(x/k,y/k);} //
    double rad(Point a,Point b){Point p = *this;return fabs(atan2(fabs((a-p)^(b-p)),(a-p)*(b-p)));} //计算该点看a,b点的角度
    double raddifference(Point a,Point b){Point p = *this;return (a.x-p.x)*(b.y-p.y)-(b.x-p.x)*(a.y-p.y);}//a,b点相对p点的角度差

};


struct polygon{
    int n;
    Point p[maxn];
    void input(int _n){
        n = _n;
        for(int i = 0; i < n; ++i) p[i].input();
    }
    void add(Point q){p[n++] = q;}
    struct cmp{
        Point p;
        cmp(const Point &p0){p = p0;}
        bool operator()(const Point &aa,const Point &bb){
            Point a = aa,b = bb;
            int d = sgn((a-p)^(b-p));
            if(d == 0) return sgn(a.distance(p)-b.distance(p))<0;
            return d > 0;
        }
    };
    void norm(){                                     //进行极角排序,首先找到最左下角的点
        Point mi = p[0];
        for(int i = 1; i < n; ++i) mi = min(mi,p[i]);
        sort(p,p+n,cmp(mi));
    }
    void getconvex(polygon &convex){                //得到凸包,内部点编号为0-n-1,如果有影响判断所有点共点或共线
        sort(p,p+n);
        convex.n = n;
        for(int i = 0;i < min(n,2); ++i)convex.p[i] = p[i];
        if(convex.n == 2 && (convex.p[0] == convex.p[1]))convex.n--;
        if(n <= 2)return ;
        int &top = convex.n;
        top = 1;
        for(int i = 2; i <n ; ++i){
            while(top && sgn((convex.p[top]-p[i])^(convex.p[top-1]-p[i])) <= 0){top--;}
            convex.p[++top] = p[i];
        }
        int temp = top;
        convex.p[++top] = p[n-2];
        for(int i = n-3; i >= 0; i--){
            while(top != temp && sgn((convex.p[top]-p[i])^(convex.p[top-1]-p[i])) <= 0)top--;
            convex.p[++top] = p[i];
        }
        if(convex.n == 2 && (convex.p[0] == convex.p[1]))convex.n--;
        convex.norm();
    }
};

Point base,rp;
int top;
double r;
polygon pol,convex;
bool cmp(Point p1,Point p2){
    if(base.raddifference(p1,p2) == 0)return base.distance(p1) < base.distance(p2);
    if(base.raddifference(p1,p2) > 0)return true;
    else return false;
}

bool judge(double a,double b,double c){
    return a*a+b*b < c*c;
}

void cal(Point p0,Point p1,Point p2){
    double p0p1 = p0.distance(p1);
    double p1p2 = p1.distance(p2);
    double p2p0 = p0.distance(p2);
    if(judge(p0p1,p1p2,p2p0) || judge(p1p2,p2p0,p0p1) || judge(p2p0,p0p1,p1p2)){
        double maxlen = max(p0p1,max(p1p2,p2p0));
        if(maxlen/2.0 > r){
            r = maxlen/2.0;
            if(maxlen == p0p1){rp.x=(p0.x+p1.x)/2.0,rp.y=(p0.y+p1.y)/2.0;}
            if(maxlen == p1p2){rp.x=(p1.x+p2.x)/2.0,rp.y=(p1.y+p2.y)/2.0;}
            if(maxlen == p2p0){rp.x=(p2.x+p0.x)/2.0,rp.y=(p2.y+p0.y)/2.0;}
        }
    }
    else{
        Point tmp;
        double a1 = p1.x - p0.x, b1 = p1.y - p0.y, c1 = (a1 * a1 + b1 * b1) / 2.0;  
        double a2 = p2.x - p0.x, b2 = p2.y - p0.y, c2 = (a2 * a2 + b2 * b2) / 2.0; 
        double d = a1*b2-a2*b1;
        tmp.x = p0.x + (c1 * b2 - c2 * b1) / d;  
        tmp.y = p0.y + (a1 * c2 - a2 * c1) / d; 
        double tmpR = p0.distance(tmp);
        if(tmpR > r)rp=tmp,r=tmpR;
    }
}
int main(){
    while(cin>>n && n){

        pol.input(n);
        pol.norm();
        base = pol.p[0];
        if(n == 1){printf("%.2f %.2f 0.00\n",pol.p[0].x,pol.p[0].y);continue;}
        pol.getconvex(convex);
        if(convex.n == 2){
            rp.x = (convex.p[0].x+convex.p[1].x)/2.0;
            rp.y = (convex.p[0].y+convex.p[1].y)/2.0;
            r = convex.p[0].distance(convex.p[1])/2.0;
            printf("%.2f %.2f %.2f\n",rp.x,rp.y,r);
            continue;
        }
        r = 0;
        for(int i = 0; i < convex.n; ++i){
            for(int j = i+1; j < convex.n; ++j){
                for(int k = j+1; k < convex.n; ++k){
                    cal(convex.p[i],convex.p[j],convex.p[k]);
                }
            }
        }
        printf("%.2f %.2f %.2f\n",rp.x,rp.y,r);
    }
    return 0;
}

 
/*
 
 
*/

2.模拟退火法

 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 
//#include 

using namespace std;
#define me(x,y) memset(x,y,sizeof x)
#define MIN(x,y) x < y ? x : y
#define MAX(x,y) x > y ? x : y
typedef long long ll;
typedef unsigned long long ull;
const double INF = 0x3f3f3f3f;
const double eps = 1e-08;
const double PI = acos(-1.0);
const int mod = 1e9+7;
const int maxn = 1000;
#define T 100
#define Delta 0.98

int n;
double r;

int sgn(double x){
    if(fabs(x) < eps) return 0;
    if(x < 0)return -1;
    else return 1;
}

struct  Point
{
	double x,y;
	double dis(Point b) {return sqrt((x-b.x)*(x-b.x)+(y-b.y)*(y-b.y));}
}p[550],pr;

void solve(){
	double t = T;
	double delta = Delta;
	pr.x = pr.y= 0;
	while(t > eps){
		int pos = 0;
		r = pr.dis(p[pos]);
		for(int i = 0; i < n; ++i){
			if(pr.dis(p[i]) > r){
				pos = i;
				r = pr.dis(p[i]);
			}
		}
		pr.x += (p[pos].x-pr.x)/r*t;
		pr.y += (p[pos].y-pr.y)/r*t;
		t *= delta;
	}

}

int main(){
    while(cin>>n && n){
		for(int i = 0; i < n; ++i) scanf("%lf%lf",&p[i].x,&p[i].y);
		solve();
		printf("%.2f %.2f %.2f\n",pr.x,pr.y,r);
    }
    return 0;
}

 
/*
 
 
*/

3.说了三种就是三种,但是万万没想到T掉了0.0,结果应该没问题,但还是放上来吧,三分法

 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 
//#include 

using namespace std;
#define me(x,y) memset(x,y,sizeof x)
#define MIN(x,y) x < y ? x : y
#define MAX(x,y) x > y ? x : y
typedef long long ll;
typedef unsigned long long ull;
const double INF = 0x3f3f3f3f;
const double eps = 1e-08;
const double PI = acos(-1.0);
const int mod = 1e9+7;
const int maxn = 1000;
#define T 100
#define Delta 0.98

int n;
double r,miny,maxy,maxx,minx;


struct  Point
{
	double x,y;
	Point(){}
	Point(double _x,double _y){x=_x,y=_y;}
	double dis(Point b) {return sqrt((x-b.x)*(x-b.x)+(y-b.y)*(y-b.y));}
	Point operator - (const Point &b) const {return Point(x-b.x,y-b.y);}
	double operator *(const Point &b) const {return x*b.x+y*b.y;}
}p[550],pr;

double cal(double x,double y){
	Point ans = Point(x,y);
	double res = 0;
	for(int i = 0; i < n; ++i) res = max(res,ans.dis(p[i]));
	return res;
}
double three_search2(double x){
	double l = miny,r = maxy;
	while(r-l > eps){
		double lmid = l+(r-l)/3;
		double rmid = r-(r-l)/3;
		if(cal(x,lmid) >= cal(x,rmid)) l = lmid;
		else r = rmid;
	}
	return l;
}
Point three_search(){
	double l = minx,r = maxx;
	while(r-l > eps){
		double lmid = l+(r-l)/3;
		double rmid = r-(r-l)/3;
		if(cal(lmid,three_search2(lmid)) >= cal(rmid,three_search2(rmid))) l = lmid;
		else r = rmid;
	}
	return Point(l,three_search2(l));
}
int main(){
    while(cin>>n && n){
		minx = miny = INF;
		maxx = maxy = -INF;
		for(int i = 0; i < n; ++i) {
			scanf("%lf%lf",&p[i].x,&p[i].y);
			minx = MIN(p[i].x,minx),miny = MIN(p[i].y,miny);
			maxx = MAX(maxx,p[i].x),maxy = MAX(maxy,p[i].y);
		}
		pr = three_search();
		r = cal(pr.x,pr.y);
		printf("%.2f %.2f %.2f\n",pr.x,pr.y,r);
    }
    return 0;
}

 
/*
 
 
*/

你可能感兴趣的:(——数学——,#,知识点,#,数学——计算几何)