BZOJ 3564 SHOI 2014 信号增幅仪 坐标变换+最小圆覆盖

题目大意:给出平面上的一些点,现在让你用一个长轴与x轴成一定角度的,长轴:短轴已知的椭圆来覆盖所有的坐标,求最小的短轴长度。

思路:很明显,这个椭圆的形状和放置状态已经给出了,但是没有办法求最小拖圆覆盖啊。采用坐标变换,将椭圆变成圆。首先我们先让长轴与x轴平行,将平面上的所有点都旋转这个角度。之后只需要让所有点的x坐标除以长轴:短轴就可以了。剩下的就是最小圆覆盖了。

注:坐标旋转公式:

x‘ = x * cos(a) - y * sin(a)

y‘ = x * sin(a) + y * cos(a)

CODE:

#define _CRT_SECURE_NO_WARNINGS

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define MAX 50010
#define PI (acos(-1.0))
using namespace std;

struct Point{
	double x,y;

	Point(double _,double __):x(_),y(__) {}
	Point() {}
	Point operator +(const Point &a)const {
		return Point(x + a.x,y + a.y);
	}
	Point operator -(const Point &a)const {
		return Point(x - a.x,y - a.y);
	}
	Point operator *(double a)const {
		return Point(x * a,y * a);
	}
	void Read() {
		scanf("%lf%lf",&x,&y);
	}
}point[MAX];

inline double Cross(const Point &p1,const Point &p2)
{
	return p1.x * p2.y - p1.y * p2.x;
}

inline double Calc(const Point &p1,const Point &p2)
{
	return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}

inline Point Mid(const Point &p1,const Point &p2)
{
	return Point((p1.x + p2.x) / 2,(p1.y + p2.y) / 2);
}

inline Point Change(const Point &v)
{
	return Point(-v.y,v.x);
}

inline void Rotate(Point &p,double alpha)
{
	p = Point(p.x * cos(alpha) - p.y * sin(alpha),p.x * sin(alpha) + p.y * cos(alpha));
}

struct Circle{
	Point o;
	double r;

	Circle(const Point &_,double __):o(_),r(__) {}
	bool InCircle(const Point &p) {
		return Calc(o,p) <= r;
	}
};

struct Line{
	Point p,v;

	Line(const Point &_,const Point &__):p(_),v(__) {}
};

inline Point GetIntersection(const Line &l1,const Line &l2)
{
	Point u = l1.p - l2.p;
	double t = Cross(l2.v,u) / Cross(l1.v,l2.v);
	return l1.p + l1.v * t;
}

int points;
double a,p;

int main()
{
	cin >> points;
	for(int i = 1; i <= points; ++i)
		point[i].Read();
	cin >> a >> p;
	random_shuffle(point + 1,point + points + 1);
	for(int i = 1; i <= points; ++i) {
		Rotate(point[i],(1 - a / 360) * 2 * PI);
		point[i].x /= p;
	}
	Circle now(point[1],.0);
	for(int i = 2; i <= points; ++i)
		if(!now.InCircle(point[i])) {
			now = Circle(point[i],.0);
			for(int j = 1; j < i; ++j)
				if(!now.InCircle(point[j])) {
					now = Circle(Mid(point[i],point[j]),Calc(point[i],point[j]) / 2);
					for(int k = 1; k < j; ++k)
						if(!now.InCircle(point[k])) {
							Line l1(Mid(point[i],point[j]),Change(point[j] - point[i]));
							Line l2(Mid(point[j],point[k]),Change(point[k] - point[j]));
							Point intersection = GetIntersection(l1,l2);
							now = Circle(intersection,Calc(intersection,point[i]));
						}
				}
		}
	cout << fixed << setprecision(3) << now.r << endl;
	return 0;
}

时间: 2024-10-11 22:32:41

BZOJ 3564 SHOI 2014 信号增幅仪 坐标变换+最小圆覆盖的相关文章

[BZOJ 3564] [SHOI2014] 信号增幅仪 【最小圆覆盖】

题目链接:BZOJ - 3564 题目分析 求最小椭圆覆盖,题目给定了椭圆的长轴与 x 轴正方向的夹角,给定了椭圆长轴与短轴的比值. 那么先将所有点旋转一个角度,使椭圆长轴与 x 轴平行,再将所有点的 x 坐标除以长轴与短轴的比值,然后就直接做最小圆覆盖了. 随机增量法,一定别忘了 random_shuffle . 代码 #include <iostream> #include <cstdlib> #include <cstring> #include <cstd

[SHTSC 2014] 信号增幅仪

最小覆盖圆算法.看着题解半蒙半抄的搞过去了… 主要参考以下http://blog.csdn.net/acdreamers/article/details/9406735http://blog.csdn.net/lthyxy/article/details/6661250http://blog.himdd.com/archives/2666 其中有一个求外心的过程是错的…害我调了好久…还把x和y搞反…可是就算是错的我居然过了80%的数据… 仍然几个疑问: (1)最小覆盖圆算法时间复杂度的证明 (2

BZOJ3564 [SHOI2014]信号增幅仪

先把椭圆长轴转到x轴上,然后把x轴按照比例缩回去,于是就变成了最小圆覆盖问题,上板子...就行 1 /************************************************************** 2 Problem: 3564 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:256 ms 7 Memory:2380 kb 8 *************************************

[bzoj 3566][SHOI 2014]概率充电器

传送门 Description SHOI 概率充电器由 n-1 条导线连通了 n 个充电元件.进行充电时,每条导线是否可以导电以概率决定,每一个充电元件自身是否直接进行充电也由概率决定. 随后电能可以从直接充电的元件经过通电的导线使得其他充电元件进行间接充电. 进入充电状态的元件个数的期望是多少呢? Solution \[ E=\sum f_i\ \ \ 其中f_i表示节点i通电的概率 \] 那么怎么求\(f_i\)呢?显然,一个点通电有三种情况:来自i的父亲节点.来自i的某个儿子节点.来自i自

bzoj-3564 信号增幅仪

题意: 给出平面上n个点和一个角度α,一个比值p: 求一个长轴与x轴夹角为α,长轴与短轴比值为p的椭圆, 包含了这n个点,且使半短轴最小: 题解: 本来只是上bz找找计算几何凸包啥的裸题刷刷,结果怎么碰上这么一个玄学的玩意... 况且这题还不用凸包: 看起来只是将圆拓展到了椭圆,但是直接按原模型乱搞似乎有些难度: 判断点和椭圆的关系需要一部转化: 两点间求椭圆,甚至三点间求椭圆都并不好搞,而且还有一个旋转的角度要考虑: 所以不能硬上,要转化模型,转化到熟悉的模型就可以搞了嘛: 将圆变成椭圆需要两

BZOJ 3566 SHOI 2014 概率充电器 概率DP

题目大意:给出一棵树,每个节点都有一个充电概率,每一条边有一个导电概率,求期望有多少个点充电. 思路:写不出题解,粘一个详细的地址:http://wyfcyx.is-programmer.com/posts/74623.html CODE: #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstring> #include <iomanip> #include <iostream> #i

【BZOJ 2823】 [AHOI2012]信号塔

2823: [AHOI2012]信号塔 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 469  Solved: 198 [Submit][Status][Discuss] Description 在野外训练中,为了确保每位参加集训的成员安全,实时的掌握和收集周边环境和队员信息非常重要,集训队采用的方式是在训练所在地散布N个小型传感器来收集并传递信息,这些传感器只与设在集训地中的信号塔进行通信,信号塔接收信号的覆盖范围是圆形,可以接收到所有分布在

bzoj 1337 最小圆覆盖

bzoj 1337 最小圆覆盖 补充一个求三角形外心的向量法.用了点积的几何意义,很实用.出处. 使用随机增量法求.首先随机打乱顺序,然后三重循环,选择当前在圆外的点更新圆,分别按照 \(1/2/3\) 个点确定圆的方式更新即可. 由于随机一个点不在前 \(i\) 个点的最小覆盖圆内的概率是 \(\frac 3 i\) ,可以证明这样的时间复杂度是 \(O(n)\) 的,这种做法可以推广到常数维度上,时间复杂度仍为 \(O(n)\) . #include<bits/stdc++.h> usin

[BZOJ 3669][NOI 2014]魔法森林(Link-Cut Tree)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3669 记得四个月之前的NOI同步赛,我还只会玩脚丫子.... 记得我当时看到这个题整个人就吓傻了,完全不知道怎么做,然后NOI同步赛就这样爆零了... 如今我学了LCT这个神器,再看这个题,感觉不再那么难了. 其实这个题的标准解法是SPFA,改得完全认不出来的SPFA. orz太神了,完全没见识过这么神犇的SPFA,NOIP 2014考了SPFA,NOI 2014也考了SPFA,