【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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章