9.25 Circle Game
时间:2019-09-25
本文章向大家介绍9.25 Circle Game,主要包括9.25 Circle Game使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题意
平面直角坐标系上有\(n\)个圆,这些圆互不相交或相切(也就是说,两个圆之间要么相离,要么是包含与被包含的关系)
每个圆有一个权值,请选择若干个圆,使得这些圆两两之间不存在包含或被包含的关系,并且所选择圆的权值和最大
解法
由于圆之间只存在包含与被包含的关系,很容易抽象出一颗树:一个圆在树上结点的父亲时包含它的半径最小的圆
因此有一个\(O(n^2)\)的做法:暴力找到每个圆的父亲,做树形\(DP\)即可。这个树形\(DP\)也很好想,因为树中同一层的结点都是兄弟结点,是不会相互影响的,所以直接把所有儿子的答案与父亲的权值比较转移即可
可以注意到复杂度瓶颈是找父亲的过程,考虑用set优化
由于圆之间只有包含与被包含的关系,我们可以发现这样一个性质:
对于一个圆,我们把它拆成上半部与下半部:从上半部出发向上走,遇到的第一个如果是上半圆,那么它所代表的整圆即是当前该圆的父亲;如果是下半圆,则是当前该圆的兄弟
我们维护一根扫描线,从左扫到右:如果扫到了一个圆的左端点,将其加入一个set中;如果扫到了某个右端点,就把它从set中删除
至于找父亲,set维护y坐标,找到当前圆上半圆的前驱,判断是一个上半圆还是下半圆从而就确定了是当前圆的父亲还是兄弟
连边后树形\(DP\)即可
代码
#include <set>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 10;
int read();
int t;
int fa[N], val[N];
int cap;
int head[N], to[N], nxt[N];
inline void add(int x, int y) { to[++cap] = y, nxt[cap] = head[x], head[x] = cap; }
struct semi {
double x, y, r;
int k, id;
double calc() const { return y - 1.000000 * k * sqrt(r * r - (x - t) * (x - t)); }
bool operator < (const semi& rhs) const {
return (id == rhs.id) ? (k > rhs.k) : (calc() < rhs.calc());
}
} c[N];
bool cmp(const semi& u, const semi& v) { return u.x + u.k * u.r < v.x + v.k * v.r; }
set<semi> s;
typedef set<semi>::iterator iter;
int DFS(int x) {
int res = 0;
for (int i = head[x]; i; i = nxt[i])
if (to[i] != fa[x]) res += DFS(to[i]);
return max(res, val[x]);
}
int main() {
int n = read();
for (int i = 1; i <= n; ++i) {
int u = i * 2, v = i * 2 - 1;
c[u].x = read(), c[u].y = read(), c[u].r = read();
c[v] = c[u];
c[u].k = 1, c[v].k = -1;
c[u].id = c[v].id = i;
val[i] = read();
}
sort(c + 1, c + n * 2 + 1, cmp);
semi ins, del;
for (int i = 1; i <= 2 * n; ++i) {
t = c[i].x + c[i].k * c[i].r;
if (c[i].k == -1) {
iter it = s.upper_bound(c[i]);
if (it != s.end())
fa[c[i].id] = (~(it -> k)) ? fa[it -> id] : it -> id;
ins = c[i], ins.k = 1;
s.insert(c[i]), s.insert(ins);
} else {
del = c[i], del.k = -1;
s.erase(c[i]), s.erase(del);
}
}
for (int i = 1; i <= n; ++i) add(fa[i], i);
int ans = 0;
for (int i = 1; i <= n; ++i)
if (!fa[i]) ans += DFS(i);
printf("%d\n", ans);
return 0;
}
int read() {
int x = 0, c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
return x;
}
原文地址:https://www.cnblogs.com/VeniVidiVici/p/11587472.html
- Django-model进阶(中介模型,查询优化,extra,整体插入)
- flask-session组件
- day10、nfs+rsync全网备份及实时同步
- Flask-信号(blinker)
- Python中的单例模式的几种实现方式的及优化
- 程序员学习python必备的4大网站,你用过几个?
- 知面不知心?AI帮你看懂对方的“小心思”
- 数据库连接池,本地线程,上下文管理
- 2018年微信小程序风口趋势预测
- 小程序走在取代APP路上
- 重磅!小程序社交立减金全面开放,快来领攻略
- VR/AR未来何去何从?
- 使用Python+Tensorflow的CNN技术快速识别验证码
- 数字化医院科研信息化管理平台的设计
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法