求助退火
查看原帖
求助退火
526519
Aisaka_Taiga楼主2023/8/22 17:02

思路是通过求出与线段所在的直线的解析式垂直的直线斜率,然后带入求出解析式,求两条直线的交点,然后判断是不是在线段上,不在就从两个端点与当前点求距离取min,在就求当前点与交点的距离。

但是样例都过不去。。

#include <bits/stdc++.h>

#define pf(x) ((x) * (x))
#define DB long double
#define N 100010

using namespace std;

int n;
DB X[N], Y[N], ans, ax, ay;

inline DB Dis(DB xx1, DB yy1, DB xx2, DB yy2){return sqrt(pf(xx1 - xx2) + pf(yy1 - yy2));}

inline DB clac(int x, int y)
{
    DB res = 0.0;
    for(int  i = 1; i <= n; i += 2)
    {
        DB k1 = (X[i + 1] - X[i]) / (Y[i + 1] - Y[i]);
        DB b1 = Y[i] - k1 * X[i];
        DB k2 = -1.0 / k1;
        DB b2 = y - k2 * x;
        DB xx = (b2 - b1) / (k1 - k2);
        DB yy = k2 * xx + b2;
        if(xx < X[i] || xx > X[i + 1])
        {
            res = max(res, min(Dis(x, y, X[i], Y[i]), Dis(x, y, X[i + 1], Y[i + 1])));
            continue;
        }
        res = max(res, Dis(x, y, xx, yy));
    }
    printf("res  :  %.7Lf\n", res);
    return res;
}

inline void SA()
{
    DB T = 1e3;
    DB xx = ax, yy = ay;
    while(T > 1e-7)
    {
        DB tx = ((rand() * 1.0 / RAND_MAX) > 0.5 ? -1 : 1) * rand() * T * 1.0 / RAND_MAX;
        DB ty = ((rand() * 1.0 / RAND_MAX) > 0.5 ? -1 : 1) * rand() * T * 1.0 / RAND_MAX;
        if(fabs(xx + tx) > 1000.0 || fabs(yy + ty) > 1000.0) continue;
        DB res = clac(xx + tx, yy + ty);
        if(res < ans) ans = res, ax = xx = xx + tx, ay = yy = yy + ty;
        else if(exp((ans - res) / T) * RAND_MAX > rand()) xx += tx, yy += ty;
        T *= 0.997;
    }
    return ;
}

signed main()
{
    srand(time(0));
    cin >> n;
    n <<= 1;
    for(int i = 1; i <= n; i +=2)
    {
        cin >> X[i] >> Y[i] >> X[i + 1] >> Y[i + 1];
        if(X[i] > X[i + 1]) swap(X[i], X[i + 1]), swap(Y[i], Y[i + 1]);
    }
    ax = ay = 500;
    ans = clac(ax, ay);
    SA();
    printf("%.8Lf\n", ans);
    return 0;
}
2023/8/22 17:02
加载中...