hdu 5017 Ellipsoid (模拟退火,计算椭球到定点的最小距离)
题意:给出椭球方程的6的参数 a,b,c,d,e,f
问椭球上的点到原点(0,0,,0)的最小距离是多少。
思路:感觉难点在于,如何保证搜到的点一直在椭球上。
一开始我考虑到了用椭球的参数方程。。。。然后发现不记得是什么了2333
然后看了题解,发现比较巧妙的做法是,只搜索x,y,然后从椭球方程中解出z。
x,y确定以后,椭球方程就变成了一个关于z的一元二次方程,可解。
由于是要求距离原点的最小距离,而现在可能得到的两个解是关于xoy平面对称的,只有z坐标不同,因此我们取距离原点近的那个z。
以及,感觉在平面上搜4个方向就好。。。没必要8个方向。。?
wa到死是因为。。。计算距离。。忘记开根号。。。。。呵呵呵呵呵呵呵呵呵我是傻逼。。。
/* ***********************************************
Author :111qqz
Created Time :2016年08月30日 星期二 20时46分05秒
File Name :code/poj/5017.cpp
************************************************ */
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#define fst first
#define sec second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ms(a,x) memset(a,x,sizeof(a))
typedef long long LL;
#define pi pair < int ,int >
#define MP make_pair
#define INF 1E20
#define MAX 1
using namespace std;
const double eps = 1E-8;
const int dx4[4]={1,0,0,-1};
const int dy4[4]={0,-1,1,0};
const int inf = 0x3f3f3f3f;
double a,b,c,d,e,f;
int dblcmp(double d)
{
return d<-eps?-1:d>eps;
}
struct point
{
double x,y,z;
point(){}
point (double _x,double _y,double _z):x(_x),y(_y),z(_z){}
double dis(point b){
double res = 0 ;
res = (x-b.x)*(x-b.x)+(y-b.y)*(y-b.y)+(z-b.z)*(z-b.z);
return sqrt(res);
}
void look()
{
printf("x:%.7f y:%.7f z:%.7f ",x,y,z);
}
};
double getZ(double x,double y)
{
double A,B,C,delta;
A = c;
B = d*y+e*x;
C = a*x*x+b*y*y+f*x*y-1;
delta = B*B-4*A*C;
// cout<<"A:"<<A<<" B:"<<B<<" C:"<<C<<" delta:"<<delta<<endl;
if (dblcmp(delta)<0) return 1E31; //无解
delta = sqrt(delta);
double z1 = (-B+delta)/2.0/A;
double z2 = (-B-delta)/2.0/A;
if (dblcmp(z1*z1-z2*z2)<0) return z1; //x,y的坐标已经确定,我们选距离(0,0,0)近的解。
else return z2;
}
double SA(point &ret)
{
double step,cur,ans=INF;
const double delta=0.99;
bool tag;
point nxt;
point target = point(0,0,0);
for ( ret = point(0,0,0),step = 1 ; step>eps ; step*=delta){
for (tag = true; tag ;){
tag = false;
for ( int i = 0 ; i < 4 ; i++){
nxt.x = ret.x + dx4[i]*step; //只搜x,y,通过解方程得到z啊巧妙地保证了点一直在椭球面上。
nxt.y = ret.y + dy4[i]*step;
nxt.z = getZ(nxt.x,nxt.y);
if (nxt.z>=1E30) continue; //无解。
cur = nxt.dis(target);
if (dblcmp(cur-ans)<0)
{
ans = cur;
ret = nxt;
tag = true;
break;
}
}
}
}
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("code/in.txt","r",stdin);
#endif
while (~scanf("%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&e,&f))
{
double ans;
point ret;
ans = SA(ret);
printf("%.7f\n",ans);
}
#ifndef ONLINE_JUDGE
fclose(stdin);
#endif
return 0;
}