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

题目链接:BZOJ - 3564

题目分析

求最小椭圆覆盖,题目给定了椭圆的长轴与 x 轴正方向的夹角,给定了椭圆长轴与短轴的比值。

那么先将所有点旋转一个角度,使椭圆长轴与 x 轴平行,再将所有点的 x 坐标除以长轴与短轴的比值,然后就直接做最小圆覆盖了。

随机增量法,一定别忘了 random_shuffle 。

代码

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

#define PI 3.14159265358979323846
#define Vector Point

typedef double LF;

const int MaxN = 50000 + 5;

const LF Eps = 1e-9;

int n;

LF Alpha, SinA, CosA;

struct Point
{
	LF x, y;

	Point() {}
	Point(LF a, LF b)
	{
		x = a; y = b;
	}

	void Rotate(LF SinA, LF CosA)
	{
		LF tx, ty;
		tx = CosA * x - SinA * y;
		ty = SinA * x + CosA * y;
		x = tx; y = ty;
	}
} P[MaxN];

inline LF Sqr(LF x) {return x * x;}

inline LF Dis(Point p1, Point p2)
{
	return sqrt(Sqr(p1.x - p2.x) + Sqr(p1.y - p2.y));
}

Point operator + (Point p1, Point p2) {return Point(p1.x + p2.x, p1.y + p2.y);}
Point operator - (Point p1, Point p2) {return Point(p1.x - p2.x, p1.y - p2.y);}
Point operator * (Point p, LF t) {return Point(p.x * t, p.y * t);}
Point operator / (Point p, LF t) {return Point(p.x / t, p.y / t);}

struct Line
{
	Point p;
	Vector v;

	Line() {}
	Line(Point p1, Point p2)
	{
		p = p1;
		v = p2 - p1;
	}
} L1, L2; 

struct Circle
{
	Point o;
	LF r;

	bool InCircle(Point p)
	{
		return Dis(o, p) <= r + Eps;
	}
} C;

inline LF Cross(Vector v1, Vector v2)
{
	return v1.x * v2.y - v2.x * v1.y;
}

Point Intersection(Line l1, Line l2)
{
	Vector u = l2.p - l1.p;
	LF t = Cross(u, l2.v) / Cross(l1.v, l2.v);
	return l1.p + (l1.v * t);
}

Vector Turn90(Vector v)
{
	return Vector(-v.y, v.x);
}

Line Verticle(Point p1, Point p2)
{
	Line ret;
	ret.p = (p1 + p2) / 2.0;
	ret.v = Turn90(p2 - p1);
	return ret;
}

int main()
{
	srand(51405102);
	scanf("%d", &n);
	int a, b;
	for (int i = 1; i <= n; ++i)
	{
		scanf("%d%d", &a, &b);
		P[i] = Point((LF)a, (LF)b);
	}
	random_shuffle(P + 1, P + n + 1);
	int ad, p;
	scanf("%d", &ad);
	Alpha = (LF)(-ad) / (LF)180 * PI;
	SinA = sin(Alpha); CosA = cos(Alpha);
	scanf("%d", &p);
	for (int i = 1; i <= n; ++i)
	{
		P[i].Rotate(SinA, CosA);
		P[i].x /= (LF)p;
	}
	C.o = P[1]; C.r = 0;
	for (int i = 1; i <= n; ++i)
	{
		if (C.InCircle(P[i])) continue;
		C.o = P[i]; C.r = 0;
		for (int j = 1; j < i; ++j)
		{
			if (C.InCircle(P[j])) continue;
			C.o = (P[i] + P[j]) / 2.0;
			C.r = Dis(C.o, P[j]);
			for (int k = 1; k < j; ++k)
			{
				if (C.InCircle(P[k])) continue;
				L1 = Verticle(P[i], P[k]);
				L2 = Verticle(P[j], P[k]);
				C.o = Intersection(L1, L2);
				C.r = Dis(C.o, P[k]);
			}
		}
	}
	printf("%.3lf\n", C.r);
	return 0;
}

  

时间: 2024-10-06 21:19:29

[BZOJ 3564] [SHOI2014] 信号增幅仪 【最小圆覆盖】的相关文章

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 *************************************

[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

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

题目大意:给出平面上的一些点,现在让你用一个长轴与x轴成一定角度的,长轴:短轴已知的椭圆来覆盖所有的坐标,求最小的短轴长度. 思路:很明显,这个椭圆的形状和放置状态已经给出了,但是没有办法求最小拖圆覆盖啊.采用坐标变换,将椭圆变成圆.首先我们先让长轴与x轴平行,将平面上的所有点都旋转这个角度.之后只需要让所有点的x坐标除以长轴:短轴就可以了.剩下的就是最小圆覆盖了. 注:坐标旋转公式: x' = x * cos(a) - y * sin(a) y' = x * sin(a) + y * cos(

BZOJ 2823 AHOI 2012 信号塔 凸包+最小圆覆盖

题目大意:给出平面上n个点,求最小圆覆盖. 思路:圆覆盖问题只与所有点中凸包上的点有关,因此先求一下凸包,然后数据范围骤减.大概是只剩下logn左右个点.这样就可以随便浪了. 先找所有三个点组成的圆,然后找两个点为直径所组成的圆. 还有就是三角形的外心公式,简直不是人推的,然后我就机制的百度了,结果如下: 不要模拟退火... 样例很坑,当你算出2.49 2.86的时候,不要认为你被卡精了,其实是你写挂了... CODE: #include <cmath> #include <cstdio

bzoj-3564 信号增幅仪

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

BZOJ 3562: [SHOI2014]神奇化合物 并查集+dfs

点击打开链接 注意到20w条边,但是询问只有1w,所以有很多边是从头到尾不变的. 首先离线处理,将从未删除的边缩点,缩点后的图的点数不会超过2w,对于每一次add或者delete,直接dfs看是否能从a走到b,然后维护一个ans. 数据不强,不然这种复杂度起码要跑10s.. #include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> using namespace st

bzoj 3566: [SHOI2014]概率充电器 树形DP

首先普及一个概率公式 P(A+B)=P(A)+P(B)-P(AB) 题意:一些充电元件和导线构成一棵树,充电元件是否能充电有2种情况, 1.它自己有qi%的概率充电 2.与它相邻的元件通过导线给它充电(导线有p%的概率导通) 求最终充了电的元件的期望 题解:首先可以将元件能否充电分成3种情况考虑, 1.它自己给自己充好了电 2.它的儿子方向给它传送了电 3.它的父亲方向给它传送了电. 对于1,题目已经给出可以直接赋值, 对于2,可以通过一次树的深度遍历求得.pson[now]=pson[now]

bzoj 1337 最小圆覆盖

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

BZOJ 2823 AHOI2012 信号塔 计算几何

题目大意:给定n个点(n<=50W),求最小圆覆盖 逗我?n<=50W?最小圆覆盖?O(n^3)? 其实数据是随机生成的 经过验证 随机生成50w的点集 平均在凸包上的点在50~60个左右 于是求凸包之后就可以随便乱搞了- - 不会写O(n^3)的最小圆覆盖 写了O(n^4)的照过 注意最小圆覆盖时要讨论有两点在圆上和有三点在圆上两种情况 --------------------以上是题解-----------以下是粗口--------------------- 出题人我*你*!!数据随机生成