1. 程式人生 > >HDU 3007 Buried memory(點集最小圓覆蓋 模擬退火解法)

HDU 3007 Buried memory(點集最小圓覆蓋 模擬退火解法)

這題和ZOJ1450是一樣的,不過這個題目我換個解法

ZOJ1450我是用標準求最小點集覆蓋求圓的方法來做的,速度很快

對於這一題目,我用的是模擬退火思想,每次像正確結果逼近

不過精度一點也不好控制,還有step也一點也不好控制,這些值都不能隨便

取,要取特定意義的值才行!

噁心的是在ZOJ上就過不了!

#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
#define maxn 1500
#define MAX(a,b) (a>b?a:b)
#define eps 1e-20
struct point{
    double x,y;
}po[maxn],cir;
int n;
double step;
double dis(point &a,point &b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double find_max(point &a){
    double ans=0,t;
    for(int i=0;i<n;i++){
        t=dis(po[i],a);
        ans=MAX(ans,t);
    }
    return ans;
}
int solve(){
    int i,j,k;
    point temp,re;
    double p,now;
    step=find_max(po[0]);
    cir=po[0];
    while(step>eps){
        temp=cir;
        temp.x+=step;
        re=temp;
        now=find_max(temp);
        temp=cir;
        temp.y+=step;
        p=find_max(temp);
        if(p < now) now=p,re=temp;
        temp=cir;
        temp.y-=step;
        p=find_max(temp);
        if(p < now) now=p,re=temp;
        temp=cir;
        temp.x-=step;
        p=find_max(temp);
        if(p < now) now=p,re=temp;
        step/=2;
        cir=re;
    }
    printf("%.2lf %.2lf %.2lf\n",cir.x,cir.y,find_max(cir));
    return 0;
}
int main(){
    int i,j,k;
    while(scanf("%d",&n),n){
        for(i=0;i<n;i++)
        scanf("%lf%lf",&po[i].x,&po[i].y);
        if(n==1){
            printf("%.2lf %.2lf %.2lf\n",po[0].x,po[0].y,0.0);
            continue;
        }
        if(n==2){
            printf("%.2lf %.2lf %.2lf\n",(po[0].x+po[1].x)/2,(po[0].y+po[1].y)/2,dis(po[0],po[1])/2);
            continue;
        }
        solve();
    }
    return 0;
}