hdu5017 Ellipsoid(旋转)

比赛的时候跳进这个大坑里,最后代码是写出来了。看到好像很多都是模拟退火做的,下面提供一个奇怪的思路吧。

ax^2+by^2+cz^2+dyz+exz+fxy=1(*)

通过一些奇特的YY我们可以知道这是由一个标准的椭球ax^2+by^2+cz^2=1旋转得到的,之所以有交叉项是因为绕了X,Y,Z轴旋转,所以我们的想法是要是能将这个椭球旋回去那么就可以知道最短的距离了。

首先我们是旋转z轴,希望使得xy项消掉,这个时候令z=0可以得到  ax^2+by^2+fxy=1

通过一些椭圆的旋转知识我们可以求出当旋转角为phi,将x,y做一个旋转代换就可以使得xy被消掉,具体的phi值求法可以百度一下椭圆,公式这里就是tan(2p)=f/(a-b)(对于上面那个式子),将这个代换弄到*里其实就会得到一个新的方程:

a‘x^2+b‘y^2+c‘z^2+d‘yz+e‘xz+f‘xy=1

这个时候f‘=0,然后我们希望通过旋转x轴将d‘=0,方法同样是令x=0得到

b‘y^2+c‘z^2+d‘yz=1

利用相同的代换可以得到新的方程

a‘‘x^2+b‘‘y^2+c‘‘z^2+d‘‘yz+e‘‘xz+f‘‘xy=1

这个时候注意,d‘‘=0,但原先的f‘‘却不一定等于0了。

同样我们再令旋转y轴,使得e‘‘=0。

经过一轮这样的操作后,我们可以发现,最后e=0是一定的,但是d和f不一定等于0,但是直觉上这样的操作只要重复的做最后一定会收敛,因此我们就重复地对这个椭球做这样的操作,做个100次(实测其实只要转4,5次)精度就已经非常足够了。

#pragma warning(disable:4996)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
#include <string>
#include <map>
using namespace std;

#define eps 1e-6
int dcmp(double x){
	return (x > eps) - (x < -eps);
}

double a, b, c, d, e, f;
double p, w, k;

double pi = acos(-1.0);

double get(double A, double B, double C)
{
	if (dcmp(B) == 0) return 0;

	if (dcmp(A - C) == 0) {
		return pi / 4;
	}
	double ret = atan(B / (A - C));
	return ret / 2;
}

double a1, a2, a3, b1, b2, b3, c1, c2, c3;

double A, B, C, D, E, F;

int main()
{
	while (~scanf("%lf%lf%lf%lf%lf%lf", &a, &b, &c, &d, &e, &f))
	{
		int T = 100;
		while (T--){
			p = 0;
			w = 0;
			k = get(a, f, b);

			a1 = cos(p)*cos(k) - sin(p)*sin(w)*sin(k);
			a2 = -cos(p)*sin(k) - sin(p)*sin(w)*cos(k);
			a3 = -sin(p)*cos(w);

			b1 = cos(w)*sin(k);
			b2 = cos(w)*cos(k);
			b3 = -sin(w);

			c1 = sin(p)*cos(k) + cos(p)*sin(w)*sin(k);
			c2 = -sin(p)*sin(k) + cos(p)*sin(w)*cos(k);
			c3 = cos(p)*cos(w);

			A = a*a1*a1 + b*b1*b1 + c*c1*c1 + d*b1*c1 + e*a1*c1 + f*a1*b1;
			B = a*a2*a2 + b*b2*b2 + c*c2*c2 + d*b2*c2 + e*a2*c2 + f*a2*b2;
			C = a*a3*a3 + b*b3*b3 + c*c3*c3 + d*b3*c3 + e*a3*c3 + f*a3*b3;
			D = a * 2 * a2*a3 + b * 2 * b2*b3 + c * 2 * c2*c3 + d*(b2*c3 + b3*c2) + e*(a2*c3 + a3*c2) + f*(a2*b3 + a3*b2);
			E = a * 2 * a1*a3 + b * 2 * b1*b3 + c * 2 * c1*c3 + d*(b1*c3 + b3*c1) + e*(a1*c3 + a3*c1) + f*(a1*b3 + a3*b1);
			F = a * 2 * a1*a2 + b * 2 * b1*b2 + c * 2 * c1*c2 + d*(b1*c2 + b2*c1) + e*(a1*c2 + a2*c1) + f*(a1*b2 + a2*b1);

			a = A; b = B; c = C; d = D; e = E; f = F;

			//haha
			//cout << a << " " << b << " " << c << " " << d << " " << e << " " << f << endl;

			p = 0;
			w = get(b, d, c);
			k = 0;

			a1 = cos(p)*cos(k) - sin(p)*sin(w)*sin(k);
			a2 = -cos(p)*sin(k) - sin(p)*sin(w)*cos(k);
			a3 = -sin(p)*cos(w);

			b1 = cos(w)*sin(k);
			b2 = cos(w)*cos(k);
			b3 = -sin(w);

			c1 = sin(p)*cos(k) + cos(p)*sin(w)*sin(k);
			c2 = -sin(p)*sin(k) + cos(p)*sin(w)*cos(k);
			c3 = cos(p)*cos(w);

			A = a*a1*a1 + b*b1*b1 + c*c1*c1 + d*b1*c1 + e*a1*c1 + f*a1*b1;
			B = a*a2*a2 + b*b2*b2 + c*c2*c2 + d*b2*c2 + e*a2*c2 + f*a2*b2;
			C = a*a3*a3 + b*b3*b3 + c*c3*c3 + d*b3*c3 + e*a3*c3 + f*a3*b3;
			D = a * 2 * a2*a3 + b * 2 * b2*b3 + c * 2 * c2*c3 + d*(b2*c3 + b3*c2) + e*(a2*c3 + a3*c2) + f*(a2*b3 + a3*b2);
			E = a * 2 * a1*a3 + b * 2 * b1*b3 + c * 2 * c1*c3 + d*(b1*c3 + b3*c1) + e*(a1*c3 + a3*c1) + f*(a1*b3 + a3*b1);
			F = a * 2 * a1*a2 + b * 2 * b1*b2 + c * 2 * c1*c2 + d*(b1*c2 + b2*c1) + e*(a1*c2 + a2*c1) + f*(a1*b2 + a2*b1);
			a = A; b = B; c = C; d = D; e = E; f = F;

			//cout << a << " " << b << " " << c << " " << d << " " << e << " " << f << endl;

			p = get(a, e, c);
			w = 0;
			k = 0;

			a1 = cos(p)*cos(k) - sin(p)*sin(w)*sin(k);
			a2 = -cos(p)*sin(k) - sin(p)*sin(w)*cos(k);
			a3 = -sin(p)*cos(w);

			b1 = cos(w)*sin(k);
			b2 = cos(w)*cos(k);
			b3 = -sin(w);

			c1 = sin(p)*cos(k) + cos(p)*sin(w)*sin(k);
			c2 = -sin(p)*sin(k) + cos(p)*sin(w)*cos(k);
			c3 = cos(p)*cos(w);

			A = a*a1*a1 + b*b1*b1 + c*c1*c1 + d*b1*c1 + e*a1*c1 + f*a1*b1;
			B = a*a2*a2 + b*b2*b2 + c*c2*c2 + d*b2*c2 + e*a2*c2 + f*a2*b2;
			C = a*a3*a3 + b*b3*b3 + c*c3*c3 + d*b3*c3 + e*a3*c3 + f*a3*b3;
			D = a * 2 * a2*a3 + b * 2 * b2*b3 + c * 2 * c2*c3 + d*(b2*c3 + b3*c2) + e*(a2*c3 + a3*c2) + f*(a2*b3 + a3*b2);
			E = a * 2 * a1*a3 + b * 2 * b1*b3 + c * 2 * c1*c3 + d*(b1*c3 + b3*c1) + e*(a1*c3 + a3*c1) + f*(a1*b3 + a3*b1);
			F = a * 2 * a1*a2 + b * 2 * b1*b2 + c * 2 * c1*c2 + d*(b1*c2 + b2*c1) + e*(a1*c2 + a2*c1) + f*(a1*b2 + a2*b1);

			a = A; b = B; c = C; d = D; e = E; f = F;

			//cout << a << " " << b << " " << c << " " << d << " " << e << " " << f << endl;
		}

		A = sqrt(1.0 / A);
		B = sqrt(1.0 / B);
		C = sqrt(1.0 / C);

		double ans = min(min(A, B), C);
		printf("%.10lf\n", ans);
	}
	return 0;
}
时间: 2024-10-08 10:03:53

hdu5017 Ellipsoid(旋转)的相关文章

ACM学习历程——HDU5017 Ellipsoid(模拟退火)(2014西安网赛K题)

---恢复内容开始--- Description Given a 3-dimension ellipsoid(椭球面) your task is to find the minimal distance between the original point (0,0,0) and points on the ellipsoid. The distance between two points (x 1,y 1,z 1) and (x 2,y 2,z 2) is defined as  Input

地球椭球体(Ellipsoid)、大地基准面(Datum)及地图投影(Projection)三者的基本概念

地球椭球体(Ellipsoid) 众所周知我们的地球表面是一个凸凹不平的表面,而对于地球测量而言,地表是一个无法用数学公式表达的曲面,这样的曲面不能作为测量和制图的基准面.假想一个扁率极小的椭圆,绕大地球体短轴旋转所形成的规则椭球体称之为地球椭球体.地球椭球体表面是一个规则的数学表面,可以用数学公式表达,所以在测量和制图中就用它替代地球的自然表面.因此就有了地球椭球体的概念. 地球椭球体有长半径和短半径之分,长半径(a)即赤道半径,短半径(b)即极半径.f=(a-b)/a为椭球体的扁率,表示椭球

HTML5 CSS3 诱人的实例: 3D立方体旋转动画

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/34120047 创意来自:http://www.html5tricks.com/demo/html5-3d-cube/index.html , 同学给我发的样例,感觉非常不错,只是实在想不出来实际的用处.可是效果非常炫~ 效果图: 知识点: 1.perspective ,transform 的复习 2.css3 backgroud实现格格背景.即面上的小格格 3. @-webki

理解HTC Vive更新——控制相机旋转和位移

本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/72188658 作者:cartzhang 一.写在前面 在HTC的vive 头盔中, 一旦Vive头盔连接都unity游戏中,就会控制所有Camera的旋转和位置. 这对于有需要的控制非头盔相机带来了烦恼. 比方说,上篇博客中,在VR中,对某个特点位置截图,就会由于头盔控制所有相机的旋转, 造成截图不精确和出现偏移. 地址:

旋转数组的最小数字

题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1.NOTE:给出的所有元素都大于0,若数组大小为0,请返回0. class Solution { public: int minNumberInRotateArray(vector<int> rotateArray) { if(rotateArray.size()==0) re

trasition,transform,旋转

<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> body{ margin: 100px; } .div1{ width: 200px; height: 150px; transform: rotate(30deg); background-color: ant

WebGL递归处理和移动?旋转?缩放

3D世界只有三种运动方式:移动.旋转.放大缩小. 使用setTimeout函数可以实现反复的循环处理,那么具体的做法是怎样的呢?setTimeout函数的第一个参数是调用的函数,第二个参数是需要经过多长时间(毫秒)后调用这个函数.如果第一个参数指定为当前所运行的函数的话,那么就可以实现持续循环了.    ?函数A被调用    ?在函数A中,使用setTimeout,并传入函数A作为参数    ?经过指定的时间后,函数A被调用    按照上面的步骤,把WebGL中绘图部分写成递归函数,就可以持续循

Opencv图像识别从零到精通(7)----图像平移、旋转、镜像

根据vc6.0c++的学习经验,如果可以很好的自己编程,让图像进行平移旋转这些操作,那么就好像能够清楚的看见图像的内部结构当然这里你怎么访问像素,这个可以自己选一种适合的,最多的是ptr指针,at也是挺多的.看着很简单的变换,可以对图像处理上手的更快,当然对于旋转可能就稍微i难了一点,不过opencv提供了resize(0,remap()等这样的函数,可以方便的让我们进行学习-特别是旋转的时候,有很多的变换,你可以任意旋转一个角度,也可能一直旋转,当然还可以保持图像大小不变的旋转和大小变换的旋转

左旋转字符串

题目 字符串左移k位后的结果 解题 旋转三次 public class Solution { public String LeftRotateString(String str,int n) { if(str == null || str.length() <=1) return str; int len= str.length(); n = n%len; char[] A = str.toCharArray(); reverse(A,0,len-1); reverse(A,0,len-n-1)