1. 程式人生 > >HDU 5017 Ellipsoid(模擬退火)

HDU 5017 Ellipsoid(模擬退火)

Sample Output
1.0000000
【思路分析】
  求橢球面上的點到原點的最短距離。網上很多說是模擬退火,個人感覺此題區域性最優解就是全域性最優解,即結果是一個單峰函式,頂多算個爬山演算法。

程式碼如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
#define r 0.99
#define inf 1e8
#define eps 1e-8
double a,b,c,d,e,f;
int direction[10][2];

void init()
{
    int x = 0;
    for(int i = -1;i <= 1;i++)
    {
        for(int j = -1;j <= 1;j++)
        {
            direction[x][0] = i;
            direction[x][1] = j;
            x++;
        }
    }
}
double distances(double x,double y,double z)
{
    return sqrt(x * x + y * y + z * z);
}
double caculateZ(double x,double y)//根據求二次方程原理求z
{
    double A = c;
    double B = d * y + e * x;
    double C = a * x * x + b * y * y + f * x * y - 1.0;
    double delta = B * B - 4.0 * A * C;

    if(delta < 0.0)
        return inf;
    else
    {
        double z1 = (-B + sqrt(delta)) / (2.0 * A);
        double z2 = (-B - sqrt(delta)) / (2.0 * A);
        if(distances(x,y,z1) < distances(x,y,z2))
            return z1;
        else
            return z2;

    }
}

int main()
{
    init();
    while(scanf("%lf %lf %lf %lf %lf %lf",&a,&b,&c,&d,&e,&f) != EOF)
    {
        double x = 0,y = 0,z = sqrt(1.0 / c);
        double step = 1.0;
        while(step > eps)
        {
            for(int i = 0;i < 9;i++)
            {
                double x1 = x + step * direction[i][0];
                double y1 = y + step * direction[i][1];
                double z1 = caculateZ(x1,y1);
                if(z1 >= inf)
                    continue;
                if(distances(x1,y1,z1) < distances(x,y,z))
                {
                    x = x1;
                    y = y1;
                    z = z1;
                }
            }
            step *= r;
        }
        printf("%.7lf\n",distances(x,y,z));
    }
    return 0;
}