【FJOI2015】最小覆盖双圆问题
题目描述
给定平面上n个点(x_1,y_1),...,(x_n,y_n)(x1,y1),...,(xn,yn),找出2个半径相同的圆R_1R1和R_2R2,覆盖给定的n个点,且半径最小。
设计一个算法,计算出所求最小覆盖双圆 R_1R1 和 R_2R2 的半径。
输入格式
输入有多个测试实例。每个实例的第1行中给出正整数n,n<1000,表示平面上有n个点。
接下来的n行中每行给出2个实数(x, y),-100000≤x≤100000,-100000≤y≤100000。
最后一行有一个0表示结束。
输出格式
对于每组数据,输出最小的符合题意的圆的半径,保留两位小数。
输入输出样例
0.00 0.00 1.00 0.00 0.00 4.00 10 0.00 0.00 0.00 3.00 1.00 6.00 2.00 2.00 3.00 5.00 5.00 3.00 6.00 3.00 9.00 5.00 10.00 5.00 11.00 3.00 0
3.05
说明/提示
对于100%的数据,n<=1000n<=1000,|x_i|,|y_i|<=100000∣xi∣,∣yi∣<=100000,(T<=10T<=10)
【题目大意】
n个点,现在给两个半径相同的圆去覆盖,求最小半径
【解题思路】
我们需要尽量可能的减少重复的点,即同时被两个圆覆盖的点
所以我们二分枚举这个中间点,让一个圆覆盖一部分
使点没有重复的被覆盖
一般情况下,我们直接按 x 排序二分
选择半径更大的一边,然后继续二分
但是这不行
因为这样实际上是用一根垂直于 x 轴的直线分两边的点
而这个直线可能会有一定斜率
所以这个中间点的查找就是一个问题
二分枚举中间的分界点,因为通过图可知
两个圆总会关于一条直线对称
两圆不相交时是一条,两圆相交时是他们的交线
我们需要一条直线将所有点分成两半
但是正像上面所说,是被交线分开的
所以两边的点并不会一定被这根线分成两半
于是我们枚举这根直线的斜率,同时为了更好的排序
我们直接旋转坐标系
旋转坐标系的过程参见线性代数
旋转这一步我觉得是这道题的关键,而其他题解都没有太说明
注意:
对于变量的使用,要注意之前他是否被变更过
调试代码的时候可以通过调整查看顺序达到更高的效率
(先看main ---> 顺序往下看)
#include<cstdio> #include<cmath> #include<algorithm> #include<iostream> using namespace std; const int MAXN = 2*1e3 + 5 ; const double INF = 1e18 ; const double an = 1.0 / 180 * acos(-1); const double eps = 1e-9; const double si = sin(an), co = cos(an); int n; double reps() { return (1.0*rand() / RAND_MAX - 0.5)*eps; } struct V {double x, y;V() {}V(double a, double b) :x(a), y(b) {}V operator+(const V&b) const { return V(x + b.x , y + b.y);}V operator-(const V&b) const { return V(x - b.x , y - b.y);}bool operator<(const V&b) const { return x < b.x; }double operator*(const V&b) const { return x * b.y - y * b.x; }double operator^(const V&b) const { return x * b.x + y * b.y; }//叉乘V operator*(double b) const { return V(x * b , y*b); }V operator/(double b) const { return V(x / b , y /b); }void rota() { double x1 = x, y1 = y;x=x1 * co - y1 * si, y=x1 * si + y1 * co; }V rot() { return V(-y, x); }double len() { return (x*x + y * y); }}p[MAXN],o; typedef V P; struct L {V s, t;L(P a,P b):s(a),t(b){}friend P cross(L a, L b) { return a.s + a.t*(b.t*(b.s - a.s)) / (b.t*a.t); }//求交点 }; P circle(P a,P b, P c) {return cross(L((a + b)*0.5, (b - a).rot()), L((a + c)*0.5, (c - a).rot())); } //求圆心 P s[MAXN]; int sgn(double x) { return x<-eps ? -1 : x>eps; } double solve(int l,int r) {double r1;if (l > r) return 0;int cnt = 0;for (int i = l; i <= r; i++)s[++cnt] = p[i];random_shuffle(s + 1, s + 1 + cnt);r1 = 0, o = s[1];for (int i = 1; i <= cnt; i++){if (sgn((s[i] - o).len() - r1)>0){o = s[i], r1 = 0;for (int j = 1; j <= i - 1; j++)if (sgn((s[j] - o).len()-r1) > 0){o = (s[i] + s[j])*0.5, r1 = (s[j] - o).len();for (int k = 1; k <= j - 1; k++)if (sgn((s[k] - o).len() - r1)>0)o = circle(s[i], s[j], s[k]), r1 = (s[i] - o).len();}}}return r1; } int main() {srand(20030719);while (scanf("%d", &n) && n){for (int i = 1; i <= n; i++){scanf("%lf%lf", &p[i].x, &p[i].y);}double ans = INF;///double cnt = 180;for (int _ = 1; _ <= 181; _++){sort(p + 1, p + 1 + n);int l = 1, r = n;//printf("**\n");while (l <= r){int mid = (l + r) >> 1;double retl = solve(1, mid); double retr = solve(mid + 1, n);//printf("**\n");double tmp = max(retl, retr);//if (retr + retl - tmp > ans) break;ans = min(tmp, ans);if (retl > retr) r = mid - 1;else l = mid + 1;}for (int i = 1; i <= n; i++)p[i].rota();}printf("%.2lf\n", sqrt(ans));}return 0; }
View Code
纪念我写完的第一道黑题
转载于:https://www.cnblogs.com/rentu/p/11347191.html
【FJOI2015】最小覆盖双圆问题相关推荐
- 697. Degree of an Array 频率最高元素的最小覆盖子数组
[抄题]: Given a non-empty array of non-negative integers nums, the degree of this array is defined as ...
- hdu 1528+hdu 1962(最小覆盖)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1528 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1 ...
- 二分图最小覆盖的Konig定理及其证明
二分图: 顶点可以分类两个集合X和Y,所有的边关联在两个顶点中,恰好一个属于集合X,另一个属于集合Y. 最小覆盖: 最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联.可以证 ...
- Leetcode 76最小覆盖子串77组合78子集
新人公众号(求支持):bigsai 专注于Java.数据结构与算法,一起进大厂不迷路! 算法文章题解全部收录在github仓库bigsai-algorithm,求star! 关注回复进群即可加入力扣打 ...
- 双指针算法之滑动窗口 | 力扣76.最小覆盖字串
本文讲解力扣76.最小覆盖字串问题 主要用到的是滑动窗口的思想 目录 76.最小覆盖字串 题目: 分析: 步骤描述: 复杂度分析: 结果 76.最小覆盖字串 题目: 给定字符串 S 以及字符串 T , ...
- 最小覆盖圆的增量算法
题意:给出平面上的一些点,要求用一个最小的圆,把所有的点包围起来. 最小覆盖圆, 增量法: 假设圆O是前i-1个点得最小覆盖圆,加入第i个点,如果在圆内或边上则什么也不做.否,新得到的最小覆盖圆肯定经 ...
- hdu3007(最小覆盖圆问题)
题目:Buried memory 最小圆覆盖,很经典的问题. 题目大概是,平面上n个点,求一个半径最小的圆,能够覆盖所有的点. 如果要求一个最小覆盖圆,这个圆至少要由三个点确定.有一种算法就是任意取三 ...
- cstring判断是否包含子串_leetcode76. 最小覆盖子串
leetcode76. 最小覆盖子串 给你一个字符串 S.一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串. 示例: 输入: S = "ADOBECODEBANC&qu ...
- P5024-保卫王国【动态dp,最小覆盖集】
正题 题目链接:https://www.luogu.org/problem/P5024 题目大意 一棵树,每次有要求 axby:a\ x\ b\ y:a x b y:表示aaa点是否必选和bbb点是否 ...
最新文章
- 深入理解argparse模块中的add_argument的参数(如action等)
- 国赛来咯,全国大学生智能汽车竞赛百度赛道正式开启
- 在.net 2.0中使用了masterpager 重写WebForm_OnSubmit()
- STM8启动分析及IAP
- win7(windows 7)系统下安装SQL2005(SQL Server 2005)图文教程
- 读【36岁IT老人再次随笔】的读后感,你会哪些计算机语言?
- android的动态注册,Android JNI 函数注册的两种方式(静态注册/动态注册)
- (学习笔记1)可见光与红外图像的特征融合(Feature Fusion)
- mysql 插入毫秒数据_MySQL存储毫秒数据的方法
- 职业学校计算机课评课,中职计算机评课稿
- 链表(c语言),c语言链表(c语言链表详解)
- 高并发之阿里云弹性伸缩的使用记录
- 接口调用频繁限制,接口限制流量
- Android微博平台设计,基于Android平台的微博系统设计与开发
- 《智能对话机器人开发实战20讲》--学习笔记--AIML基础功能拓展-与互联网的集成
- JavaScript进阶 - 第9章 DOM对象,控制HTML元素
- COALESCE()函数 一个非常有用的函数
- 积木盒子工作室第一次博客汇总
- qq空间、微信好友、邮件、短信分享
- 申请软件著作权登记没有源代码怎么办?如果有源代码怎么快速下证?
热门文章
- 微软推出VS Code新特性,为TypeScript和JavaScript用户提供AI辅助开发功能
- Android 通过反射让SQlite建表
- Linux 系统 rpm安装ipvsadm.src.rpm
- Silverlight 5.0 之前的SaveFileDialog的FilterIndex 错误
- 寻找U2OS中表达的基因及其promoter并用于后续annotation
- 代码质量与规范,那些年你欠下的技术债
- ZigBee TI ZStack CC2530 2.4 IAR软件版本
- TYVJ P1069 cowtour 看不懂题意
- 解决在Ubuntu下打开txt文件乱码的问题
- PL/SQL程序设计 第一章 PL/SQL 程序设计简介