【POJ2069&HDU3007】模拟退火算法之最小球/圆覆盖

启蒙博客:https://blog.csdn.net/AI_BigData_wh/article/details/77943787?locationNum=2&fps=1

POJ2069:最小球覆盖


被精度搞死。。POJ做题经常被精度卡到怀疑人生。。好感-1-1-1...-1

队友的模拟退火的模版好像是错的(但是能过HDU3007,很玄学了)。初识温度的设置不能太大,会影响最终结果的准确度。

ac代码:

#include <iostream>
#include <cmath>
using namespace std;
const int maxn = 40;
const double eps = 1e-7;
const double DINF = 0x7fffffff;
const double initT = 400;//设小了可能会wa,POJ2069开到500会wa,200-400可行
struct Point{
    double x, y, z;
    Point(double x = 0, double y = 0, double z = 0):x(x),y(y),z(z){}
};
Point p[maxn];
int n;
double dist(Point a, Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
double sa()
{
    double ans = DINF, T = initT;//T相当与迭代次数,多次结果更准确
    Point ansp = Point(0,0,0);// ansp记录最小球的圆心
    while(T > eps)
    {
        double maxd = -1;
        int k = 0;
        for(int i = 0; i < n; i++)
            if(dist(ansp, p[i]) > maxd)
            {
                maxd = dist(ansp, p[i]);
                k = i;//不单独开一个点maxd记录和当前圆心距离最远的点,会wa,精度问题吧
            }
        ans = min(ans, maxd);//更新最小半径
        ansp.x += (p[k].x-ansp.x)*T/maxd;
        ansp.y += (p[k].y-ansp.y)*T/maxd;
        ansp.z += (p[k].z-ansp.z)*T/maxd;
        T *= 0.98;//降温
    }
    return ans;
}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    while(scanf("%d", &n))
    {
        if(n == 0) break;
        for(int i = 0; i < n; i++) scanf("%lf %lf %lf", &p[i].x, &p[i].y, &p[i].z);
        printf("%.5lf\n", sa());
    }
    return 0;
}

HDU3007: 最小圆覆盖


数据比较水吧。用队友的模版也能过,两个都贴上吧。!(◎_◎;)

mine:

#include <iostream>
#include <cmath>
using namespace std;
const int maxn = 550;
const double eps = 1e-7;
const double DINF = 0x7fffffff;
const double initT = 400;//设小了可能会wa,POJ2069开到500会wa
struct Point{
    double x, y;
    Point(double x = 0, double y = 0):x(x),y(y){}
};
Point p[maxn];
int n;
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 sa()
{
    double ans = DINF, T = initT;//T相当与迭代次数,多次结果更准确
    Point ansp = Point(0,0);//ansp记录最小球的圆心
    while(T > eps)
    {
        double maxd = -1;
        int k = 0;
        for(int i = 0; i < n; i++)
            if(dist(ansp, p[i]) > maxd)
            {
                maxd = dist(ansp, p[i]);
                k = i;
            }
        ans = min(ans, maxd);//更新最小半径
        ansp.x += (p[k].x-ansp.x)*T/maxd;
        ansp.y += (p[k].y-ansp.y)*T/maxd;
        T *= 0.98;//降温
    }
    printf("%.2lf %.2lf %.2lf\n", ansp.x, ansp.y, ans);
}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    while(scanf("%d", &n))
    {
        if(n == 0) break;
        for(int i = 0; i < n; i++) scanf("%lf %lf", &p[i].x, &p[i].y);
        sa();
    }
    return 0;
}

WJX‘s:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=550;
const double eps=1e-3;       //精度
const double start_T=1000;   //初始温度
const double rate=0.98;      //温度下降速率
struct point
{
    double x;
    double y;
} p[maxn];
int N;
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 solve()
{
    double T=start_T;
    point ans_p={0,0};  //初始点
    double ans=1e99;      //预设一个较大值
    while(T>eps)
    {
        point maxd_p=p[1];
        for(int i=2;i<=N;i++)
        {
            if(dist(ans_p,p[i])>dist(ans_p,maxd_p))
                maxd_p=p[i];
        }
        //找到距离ans_p最远的点,maxd_p
        ans=min(ans,dist(ans_p,maxd_p));
        ans_p.x+=(maxd_p.x-ans_p.x)*(T/start_T);    //以一定概率靠近maxd_p
        ans_p.y+=(maxd_p.y-ans_p.y)*(T/start_T);
        T*=rate;
    }
    printf("%.2lf %.2lf %.2lf\n", ans_p.x, ans_p.y, ans);
}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    while(scanf("%d",&N) && N)
    {
        for (int i = 1; i <= N; i++)
            scanf("%lf %lf", &p[i].x, &p[i].y);
        solve();
    }
    return 0;
}
发布了299 篇原创文章 · 获赞 81 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Cassie_zkq/article/details/102490814