标签:
题目链接;
UVALive 4986 Dome of Circus
题意:
在空间中给
数据范围:
分析;
首先把三维的点转成二维的,因为是圆锥覆盖,所以我们只需要知道点到圆锥轴的距离和点的纵坐标就好了。那么可得:
一元可微函数在某个区间上是凸的,当且仅当它的导数在该区间上单调不减。
于是我们可以三分枚举底面圆半径
但是我们也可以换个思路。回到最初的问题,我们是想在第一象限内画一条斜率为负的直线,并且假设和横轴、纵轴分别交于
在看看上面的推导根据
我们通过求凸包边和横轴的交点和直线
我们通过求凸包,枚举凸包边,比较
但是写起来太麻烦了。。。。而且边界情况比较多。
下面的两个代码都是AC了的。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N = 100010;
const double eps = 1e-8;
int n;
inline int sgn(double x)
{
if(fabs(x) <= eps) return 0;
else if(x > 0.0) return 1;
else return -1;
}
struct Point {
double x, y;
Point() {}
Point(double _x, double _y): x(_x), y(_y) {}
}point[MAX_N];
inline double GetHeight(double r)
{
double res = -1.0;
for(int i = 0; i < n; ++i) {
double h = point[i].y * r / (r - point[i].x);
if(sgn(h - res) > 0) res = h;
}
return res;
}
int main()
{
while(~scanf("%d", &n)) {
double MinR = -1.0;
for(int i = 0; i < n; ++i) {
double a, b, c;
scanf("%lf%lf%lf", &a, &b, &c);
point[i] = Point(sqrt(a * a + b * b), c);
if(sgn(point[i].x - MinR) > 0) MinR = point[i].x;
}
double low = MinR, high = 1e10, mid, midmid, v1, v2;
for(int i = 0; i < 100; ++i) {
mid = (low + high) / 2.0;
midmid = (mid + high) / 2.0;
v1 = GetHeight(mid) * mid * mid;
v2 = GetHeight(midmid) * midmid * midmid;
if(sgn(v2 - v1) < 0) low = mid;
else high = midmid;
}
printf("%.3lf %.3lf\n", GetHeight(mid), mid);
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#include <vector>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N = 10010;
const double eps = 1e-8;
inline int sgn(double x)
{
if(fabs(x) <= eps) return 0;
else if(x > 0) return 1;
else return -1;
}
struct Point {
double x, y;
Point() {}
Point(double _x, double _y): x(_x), y(_y) {}
Point operator - (const Point& rhs) const {
return Point(x - rhs.x, y - rhs.y);
}
Point operator + (const Point& rhs) const {
return Point(x + rhs.x, y + rhs.y);
}
Point operator * (const double& d) const {
return Point(x * d, y * d);
}
Point operator / (const double& d) const {
return Point(x / d, y / d);
}
double dis(const Point& rhs) const {
return sqrt((x - rhs.x) * (x - rhs.x) + (y - rhs.y) * (y - rhs.y));
}
double cross(const Point& rhs) const {
return x * rhs.y - y * rhs.x;
}
double dot(const Point& rhs) const {
return x * rhs.x + y * rhs.y;
}
}point[MAX_N], vertex[MAX_N];
int n;
Point center = Point(0, 0);
bool cmp_pola_angle(Point a, Point b)
{
double res = (a - center).cross(b - center);
if(sgn(res) != 0) return sgn(res) > 0;
else return a.dis(center) < b.dis(center);
}
int GetConvex()
{
sort(point, point + n, cmp_pola_angle);
int k = 0;
for (int i = 0; i < n; ++i) {
while(k > 1 && sgn((vertex[k - 1] - vertex[k - 2]).cross(point[i] - vertex[k - 1])) <= 0) {
k--;
}
vertex[k++] = point[i];
}
int m = k;
for (int i = n - 2; i >= 0; --i) {
if(k > m && sgn((vertex[k - 1] - vertex[k - 2]).cross(point[i] - vertex[k - 1])) <= 0) {
k--;
}
vertex[k++] = point[i];
}
if(k > 1) k--;
return k;
}
inline double GetX(Point a, Point b)
{
return (a.x * b.y - a.y * b.x) / (b.y - a.y);
}
inline double GetY(Point a, Point b)
{
return (a.y * b.x - a.x * b.y) / (b.x - a.x);
}
int main()
{
while(~scanf("%d", &n)) {
for(int i = 0; i < n; ++i) {
double a, b, c;
scanf("%lf%lf%lf", &a, &b, &c);
point[i] = Point(sqrt(a * a + b * b), c);
}
int m = GetConvex();
double r, h, v;
if(m == 1) {
printf("%.3lf %.3lf\n", 3 * vertex[0].y, 1.5 * vertex[0].x);
continue;
} else if(m == 2) {
if(vertex[0].y > vertex[1].y) swap(vertex[0], vertex[1]);
double tmp = GetX(vertex[1], vertex[0]);
if(1.5 * vertex[1].x < tmp) {
if(1.5 * vertex[0].x >= tmp) {
r = tmp, h = GetY(vertex[1], vertex[0]);
} else {
r = 1.5 * vertex[0].x, h = 3.0 * vertex[0].y;
}
} else {
if(1.5 * vertex[0].x > tmp) {
r = 1.5 * vertex[1].x, h = 3.0 * vertex[1].y;
} else {
double r1 = vertex[0].x * 1.5, h1 = vertex[0].y * 3;
double r2 = vertex[1].x * 1.5, h2 = vertex[1].y * 3;
if(r1 * r1 * h1 < r2 * r2 * h2) {
r = r1, h = h1;
} else {
r = r2, h = h2;
}
}
}
printf("%.3lf %.3lf\n", h, r);
continue;
}
vertex[m] = vertex[0];
double MaxX = -1.0, MaxY = -1.0;
int idx, idy;
for(int i = 0; i < m; ++i) {
if(sgn(vertex[i].x - MaxX) > 0) {
MaxX = vertex[i].x;
idx = i;
}
if(sgn(vertex[i].y - MaxY) > 0) {
MaxY = vertex[i].y;
idy = i;
}
}
if(idx == idy) {
printf("%.3lf %.3lf\n", vertex[idx].y * 3.0, vertex[idx].x * 1.5);
continue;
}
double pre, cur, r2, h2, v2;
pre = GetX(vertex[(idx + 1) % m], vertex[idx]);
if(1.5 * vertex[idx].x <= pre) {
r = 1.5 * vertex[idx].x, h = 3.0 * vertex[idx].y;
v = r * r * h;
}
v = 1e20;
for(int i = idx + 1; i < idy; ++i) {
if(sgn(vertex[i].y - vertex[i - 1].y) < 0) continue;
pre = GetX(vertex[i], vertex[i - 1]);
cur = GetX(vertex[i + 1], vertex[i]);
if(1.5 * vertex[i].x < pre) {
r2 = pre, h2 = GetY(vertex[i], Point(pre, 0));
} else if(1.5 * vertex[i].x < cur) {
r2 = 1.5 * vertex[i].x, h2 = 3 * vertex[i].y;
}else {
r2 = cur, h2 = GetY(vertex[i], Point(cur, 0));
}
v2 = r2 * r2 * h2;
if(sgn(v2 - v) < 0) {
v = v2, r = r2, h = h2;
}
}
pre = GetX(vertex[idy], vertex[idy - 1]);
if(1.5 * vertex[idy].x >= pre) {
r2 = 1.5 * vertex[idy].x, h2 = 3.0 * vertex[idy].y;
v2 = r2 * r2 * h2;
if(sgn(v2 - v) < 0) {
v = v2, r = r2, h = h2;
}
} else {
r2 = pre, h2 = GetY(vertex[idy], Point(pre, 0));
v2 = r2 * r2 * h2;
if(sgn(v2 - v) < 0) {
v = v2, r = r2, h = h2;
}
}
printf("%.3lf %.3lf\n", h, r);
}
return 0;
}
UVALive 4986 Dome of Circus(三分、凸包、凸性函数)
标签:
原文地址:http://blog.csdn.net/ramay7/article/details/51975712