spoj 145 Aliens(增量法+最小包围圈)

【题目大意】:给出你T个case。每个case有n个点,叫你求这个点的半径和圆心坐标,使得这个圆覆盖所有的点(n<=100000)


【解题思路】:曾经在zoj上做过一道最小圆的覆盖,但是那道题的点只有100,当初是暴力做的。显然碰到这个数据量是行不通的,我们可以采取dfs进行增量,或者利用随机重排进行增量,二者在spoj上测试的时间差距不大,网络模版testing。


【代码】:

dfs实现增量

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <cctype>
#include <map>
#include <iomanip>
                   
using namespace std;
                   
#define eps 1e-8
#define pi acos(-1.0)
#define inf 1<<30
#define linf 1LL<<60
#define pb push_back
#define lc(x) (x << 1)
#define rc(x) (x << 1 | 1)
#define lowbit(x) (x & (-x))
#define ll long long


int n;

struct Point{
    double x;
    double y;
}pt[1005];

struct Traingle{
    struct Point p[3];
};

struct Circle{
    struct Point center;
    double r;
}ans;
//计算两点距离

double Dis(struct Point p, struct Point q){
    double dx=p.x-q.x;
    double dy=p.y-q.y;
    return sqrt(dx*dx+dy*dy);
}

//计算三角形面积
double Area(struct Traingle ct){
    return fabs((ct.p[1].x-ct.p[0].x)*(ct.p[2].y-ct.p[0].y)-(ct.p[2].x-ct.p[0].x)*(ct.p[1].y-ct.p[0].y))/2.0;
}

//求三角形的外接圆,返回圆心和半径(存在结构体"圆"中)
struct Circle CircumCircle(struct Traingle t){
    struct Circle tmp;
    double a,b,c,c1,c2;
    double xA,yA,xB,yB,xC,yC;
    a=Dis(t.p[0],t.p[1]);
    b=Dis(t.p[1],t.p[2]);
    c=Dis(t.p[2],t.p[0]);
    //根据S = a * b * c / R / 4;求半径R
    tmp.r=(a*b*c)/(Area(t)*4.0);
    xA=t.p[0].x;
    yA=t.p[0].y;
    xB=t.p[1].x;
    yB=t.p[1].y;
    xC=t.p[2].x;
    yC=t.p[2].y;
    c1=(xA*xA+yA*yA-xB*xB-yB*yB)/2;
    c2=(xA*xA+yA*yA-xC*xC-yC*yC)/2;
    tmp.center.x=(c1*(yA-yC)-c2*(yA-yB))/((xA-xB)*(yA-yC)-(xA-xC)*(yA-yB));
    tmp.center.y=(c1*(xA-xC)-c2*(xA-xB))/((yA-yB)*(xA-xC)-(yA-yC)*(xA-xB));
    return tmp;
}

//确定最小包围圆
struct Circle MinCircle(int num, struct Traingle ct){
    struct Circle ret;
    if (num==0) ret.r=0.0;
    else if (num==1){
        ret.center=ct.p[0];
        ret.r = 0.0;
    }
    else if (num==2){
        ret.center.x=(ct.p[0].x+ct.p[1].x)/2.0;
        ret.center.y=(ct.p[0].y+ct.p[1].y)/2.0;
        ret.r=Dis(ct.p[0], ct.p[1])/2.0;
    }
    else if(num==3) ret=CircumCircle(ct);
    return ret;
}

//递归实现增量算法
void Dfs(int x, int num, struct Traingle ct){
    int i, j;
    struct Point tmp;
    ans = MinCircle(num, ct);
    if (num==3) return;
    for (i=1; i<=x; i++)
        if (Dis(pt[i],ans.center)>ans.r){
            ct.p[num]=pt[i];
            Dfs(i-1,num+1,ct);
            tmp=pt[i];
            for (j=i; j>=2; j--)
                pt[j]=pt[j-1];
            pt[1]=tmp;
        }
}

void Solve(int n){
    struct Traingle ct;
    Dfs(n,0,ct);
}

int main(){
    int T;
    cin >> T;
    while (T--){
        scanf("%d",&n);
       if (n==0) break; 
       for (int i=1; i<=n; i++)
            scanf("%lf %lf",&pt[i].x,&pt[i].y);
        Solve(n);
        printf("%.2f\n",ans.r);
        printf("%.2f %.2f\n",ans.center.x,ans.center.y);
    }
    return 0;
}

随机重排增量

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <cctype>
#include <map>
#include <iomanip>
                   
using namespace std;
                   
#define eps 1e-10
#define pi acos(-1.0)
#define inf 1<<30
#define linf 1LL<<60
#define pb push_back
#define lc(x) (x << 1)
#define rc(x) (x << 1 | 1)
#define lowbit(x) (x & (-x))
#define ll long long

const int N=100010;
int n;

struct cpoint {
    double x, y;
}cp[N];

int dcmp(double x) {
    if (x < -eps) return -1; else return x > eps;
}

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

double dis(cpoint p1,cpoint p2) {
    return sqrt(sqr(p1.x-p2.x)+sqr(p1.y-p2.y));
}

void center(cpoint p0, cpoint p1, cpoint p2, cpoint &cp) { //三角形外心
    double a1=p1.x-p0.x,b1=p1.y-p0.y,c1=(sqr(a1)+sqr(b1))/2;
    double a2=p2.x-p0.x,b2=p2.y-p0.y,c2=(sqr(a2)+sqr(b2))/2;
    double d=a1*b2-a2*b1;
    cp.x=p0.x+(c1*b2-c2*b1)/d;
    cp.y=p0.y+(a1*c2-a2*c1)/d;
}

void MinCir(cpoint cp[], int n, cpoint &c, double &r) {
    random_shuffle(cp, cp + n);
    c = cp[0]; r = 0;
    for (int i = 1; i < n; ++i) {
        if (dcmp(dis(cp[i], c) - r) <= 0) continue;
        c = cp[i]; r = 0;
        for (int j = 0; j < i; ++j) {
            if (dcmp(dis(cp[j], c) - r) <= 0) continue;
            c.x = (cp[i].x + cp[j].x) / 2;
            c.y = (cp[i].y + cp[j].y) / 2;
            r = dis(c, cp[j]);
            for (int k = 0; k < j; ++k) {
                if (dcmp(dis(cp[k], c) - r) <= 0) continue;
                center(cp[i], cp[j], cp[k], c);
                r = dis(c, cp[k]);
            }
        }
    }
}

void solve() {
    scanf("%d",&n);
    for (int i=0; i<n; ++i) {
        scanf("%lf%lf",&cp[i].x,&cp[i].y);
    }
    cpoint c;
    double r;
    MinCir(cp,n,c,r);
    printf("%.2f\n%.2f %.2f\n",r,c.x,c.y);
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}


 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值