2018南京区域赛D-Country Meow【模拟退火、三分】

题意:给你n个点的三维坐标,让你求一个点使得这个点到三个点的最大距离最小,也就是最小覆盖问题。

三分

思路:相当于对x,y,z坐标进行进行三分,找到最优解。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
struct node
{
    double x, y, z;
}a[maxn];
int n;
double dis(double x, double y, double z)
{
    double ret = 0;
    for(int i = 0; i < n; ++i)
    {
        ret = max(ret, sqrt((a[i].x - x) * (a[i].x - x) + (a[i].y - y) * (a[i].y - y) + (a[i].z - z) * (a[i].z - z)));
    }
    return ret;
}
double slove(double c[], int num)
{
    if(num >= 3)
        return dis(c[0], c[1], c[2]);
    double l = -1e5, r = 1e5;
    double midl, midr, ans;
    while(r - l > 1e-6)
    {
        midl = l + (r - l) / 3;
        midr = r - (r - l) / 3;
        c[num] = midl;
        double ans1 = slove(c, num + 1);
        c[num] = midr;
        double ans2 = slove(c, num + 1);
        if(ans1 > ans2)
        {
            ans = ans2;
            l = midl;
        }
        else
        {
            ans = ans1;
            r = midr;
        }
    }
    return ans;
}

int main()
{
    scanf("%d", &n);
    for(int i = 0; i < n; ++i)
        scanf("%lf%lf%lf", &a[i].x, &a[i].y, &a[i].z);
    double c[4];
    double ans = slove(c, 0);
    printf("%.10f\n", ans);
    return 0;
}

模拟退火

思路:首先不知道模拟退火的可以看看这篇文章,讲的很棒,打开链接

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e2 + 10;
struct node
{
    double x, y, z;
}a[maxn];
int n;
double X, Y, Z, ans;
double dis(double x, double y, double z)
{
    double ret = 0;
    for(int i = 0; i < n; ++i)
    {
        ret = max(ret, sqrt((a[i].x - x) * (a[i].x - x) + (a[i].y - y) * (a[i].y - y) + (a[i].z - z) * (a[i].z - z)));
    }
    return ret;
}
void slove()
{
    double T = 10, r = 0.995; //初始温度、降温
    ans = dis(X, Y, Z);
    while(T > 1e-10)
    {
        double x = X + (rand() * 2 - RAND_MAX) * T; 
        double y = Y + (rand() * 2 - RAND_MAX) * T;
        double z = Z + (rand() * 2 - RAND_MAX) * T;
        double res = dis(x, y, z);
        if(res < ans) //条件满足更新最优解
        {
            ans = res;
            X = x, Y = y, Z = z;
        }
        else if(exp((ans - res) / T) * RAND_MAX > rand()) //不满足则随机更新,跳出局部最优解
        {
            X = x, Y = y, Z = z;
        }
        T *= r; //降温
    }
}

int main()
{
    srand(time(NULL));
    scanf("%d", &n);
    for(int i = 0; i < n; ++i)
    {
        scanf("%lf%lf%lf", &a[i].x, &a[i].y, &a[i].z);
        X += a[i].x, Y += a[i].y, Z += a[i].z;
    }
    X /= n, Y /= n, Z /= n;
    slove();
    printf("%.10f\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41785863/article/details/89432434