hdu 5017 Ellipsoid (模拟退火,计算椭球到定点的最小距离)

hdu 5017 题目链接

题意:给出椭球方程的6的参数 a,b,c,d,e,f 

问椭球上的点到原点(0,0,,0)的最小距离是多少。

思路:感觉难点在于,如何保证搜到的点一直在椭球上。

一开始我考虑到了用椭球的参数方程。。。。然后发现不记得是什么了2333

然后看了题解,发现比较巧妙的做法是,只搜索x,y,然后从椭球方程中解出z。

x,y确定以后,椭球方程就变成了一个关于z的一元二次方程,可解。

由于是要求距离原点的最小距离,而现在可能得到的两个解是关于xoy平面对称的,只有z坐标不同,因此我们取距离原点近的那个z。

以及,感觉在平面上搜4个方向就好。。。没必要8个方向。。?

2016-08-31 14-49-34 的屏幕截图

wa到死是因为。。。计算距离。。忘记开根号。。。。。呵呵呵呵呵呵呵呵呵我是傻逼。。。

  1/* ***********************************************
  2Author :111qqz
  3Created Time :2016年08月30日 星期二 20时46分05秒
  4File Name :code/poj/5017.cpp
  5 ************************************************ */
  6#include <cstdio>
  7#include <cstring>
  8#include <iostream>
  9#include <algorithm>
 10#include <vector>
 11#include <queue>
 12#include <set>
 13#include <map>
 14#include <string>
 15#include <cmath>
 16#include <cstdlib>
 17#include <ctime>
 18#define fst first
 19#define sec second
 20#define lson l,m,rt<<1
 21#define rson m+1,r,rt<<1|1
 22#define ms(a,x) memset(a,x,sizeof(a))
 23typedef long long LL;
 24#define pi pair < int ,int >
 25#define MP make_pair
 26#define INF 1E20
 27#define MAX 1
 28using namespace std;
 29const double eps = 1E-8;
 30const int dx4[4]={1,0,0,-1};
 31const int dy4[4]={0,-1,1,0};
 32const int inf = 0x3f3f3f3f;
 33double a,b,c,d,e,f;
 34int dblcmp(double d)
 35{
 36    return d<-eps?-1:d>eps;
 37}
 38struct point
 39{
 40    double x,y,z;
 41    point(){}
 42    point (double _x,double _y,double _z):x(_x),y(_y),z(_z){}
 43    double dis(point b){
 44	double res = 0 ;
 45	res = (x-b.x)*(x-b.x)+(y-b.y)*(y-b.y)+(z-b.z)*(z-b.z);
 46	return sqrt(res);
 47    }
 48    void look()
 49    {
 50	printf("x:%.7f y:%.7f z:%.7f ",x,y,z);
 51    }
 52};
 53double getZ(double x,double y)
 54{
 55    double A,B,C,delta;
 56    A = c;
 57    B = d*y+e*x;
 58    C = a*x*x+b*y*y+f*x*y-1;
 59    delta = B*B-4*A*C;
 60    //    cout<<"A:"<<A<<" B:"<<B<<" C:"<<C<<" delta:"<<delta<<endl;
 61    if (dblcmp(delta)<0) return 1E31; //无解
 62    delta = sqrt(delta);
 63    double z1 = (-B+delta)/2.0/A;
 64    double z2 = (-B-delta)/2.0/A;
 65    if (dblcmp(z1*z1-z2*z2)<0) return z1;   //x,y的坐标已经确定,我们选距离(0,0,0)近的解。
 66    else return z2;
 67}
 68double SA(point &ret)
 69{
 70    double step,cur,ans=INF;
 71    const double delta=0.99;
 72    bool tag;
 73    point nxt;
 74    point target = point(0,0,0);
 75    for ( ret = point(0,0,0),step = 1 ; step>eps ; step*=delta){
 76	for (tag = true; tag ;){
 77	    tag = false;
 78	    for ( int i = 0 ; i < 4 ; i++){
 79		nxt.x = ret.x + dx4[i]*step;  //只搜x,y,通过解方程得到z啊巧妙地保证了点一直在椭球面上。
 80		nxt.y = ret.y + dy4[i]*step;
 81	        nxt.z = getZ(nxt.x,nxt.y);
 82		if (nxt.z>=1E30) continue; //无解。
 83		cur = nxt.dis(target);
 84		if (dblcmp(cur-ans)<0)
 85		{
 86		    ans = cur;
 87		    ret = nxt;
 88		    tag = true;
 89		    break;
 90		}
 91	    }
 92	}
 93    }
 94    return ans;
 95}
 96int main()
 97{
 98#ifndef  ONLINE_JUDGE 
 99    freopen("code/in.txt","r",stdin);
100#endif
101    while (~scanf("%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&e,&f))
102    {
103	double ans;
104	point ret;
105	ans = SA(ret);
106	printf("%.7f\n",ans);
107    }
108#ifndef ONLINE_JUDGE  
109    fclose(stdin);
110#endif
111    return 0;
112}