首页 > 代码库 > Disks
Disks
题目链接
- 题意:
给n个圆形盘子的半径,按照顺序一个一个放到x轴正无穷处(与x轴相切),然后向x轴负方向滚动直到碰到第一个盘子或者接触到y轴就停止。输出哪些盘子去掉后,右边界不会变小 - 分析:
这个题的总体思路比较简单,就是枚举出之前所有的盘子就可以知道当前盘子的位置了。既然要去掉后右边界不变,那么可以先找到右边界上的盘子,问题来了,如果有多个呢?可以想到,选id较小的那个就可以了,因为这个圆的半径必然比较大,和之前的盘子肯定有接触;然后就是看一下和当前盘子接触的有哪些,如果有多个呢?同样的,还是找id较小的那个,因为半径大,和之前的盘子相切
这个题难点不在计算,而在于多种情况的处理上
const double eps = 1e-6; const int maxn = 1100; inline int dcmp(double x) { if (fabs(x) < eps) return 0; return x < 0 ? -1 : 1; } struct Point { double x, y; Point(double x = 0, double y = 0) : x(x), y(y) {} }; struct Circle { Point p; double r; } ipt[maxn]; double x[maxn]; int pre[maxn]; bool vis[maxn]; int ans = 0; void dfs(int u) { ans--; vis[u] = true; if (pre[u] == u) return; if (!vis[pre[u]]) dfs(pre[u]); } int main() { //freopen("0.txt", "r", stdin); int n; while (~RI(n)) { ans = n; FE(i, 1, n) { scanf("%lf", &ipt[i].r); ipt[i].p.y = ipt[i].r; pre[i] = i; vis[i] = false; } ipt[1].p.x = ipt[1].r; double Max = ipt[1].p.x + ipt[1].r; int id = 1; FE(i, 2, n) { double xmax = ipt[i].r; FE(j, 1, i - 1) { x[j] = 2 * sqrt(ipt[i].r * ipt[j].r) + ipt[j].p.x; if (dcmp(xmax - x[j]) < 0) xmax = x[j]; } FE(j, 1, i - 1) { if (dcmp(x[j] - xmax) == 0) { pre[i] = j; break; } } ipt[i].p.x = xmax; if (dcmp(ipt[i].p.x + ipt[i].r - Max) > 0) { Max = ipt[i].p.x + ipt[i].r; id = i; } } dfs(id); WI(ans); FE(i, 1, n) { if (!vis[i]) WI(i); } } return 0; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。