计算"minimal"值
Count "minimal" values
问题:
我有一个 n 个向量的输入:
(x, y, z): x ∈ {1..n},y ∈ {1..n},z ∈ {1..n} (every "dimension" is set(1..n))
*I mean that in one vector x,y,z can be the same(x=y=z),
but for ∀v1,v2 => x1≠x2, y1≠y2, z1≠z2
v1>v2 if and only if x1>x2,y1>y2,z1>z2.
lets denote vector v1 "minimal" if and only if ∄v ∈ input: v>v1
任务是计算输入中的最小向量。
源:
我在本地编程竞赛的任务中发现了这个问题。
(翻译的)表述为:
n people participeted in competion. competion had three phases(every competitor
took part in every stage). denote that the participant is better then
participant b, if a ranks in all three stages is higher then participant b ranks.
participant c is the best, if there is no such participant who is better
than participant c. output the number of best participants.
1<=n<=100000时间限制:1 秒
我的尝试和想法
第一个想法是创建类 Result(对于竞争对手的结果),重载运算符>(或<),就像:
bool operator > (const Score &s) const
{
if (first_result > s.first_result)
if (second_result > s.second_result)
return third_result > s.third_result;
return false;
}
并构建任何基于数组(例如最小堆)的数组,允许查找最小值(使用 <)并计算它们(我想我刚刚按照这种方式"重新创建"了一个糟糕的堆排序变体)。在我这次尝试失败后,我尝试了芬威克树(二元索引树)来完成相同的任务。
但后来我明白我的方法不正确(不是好的类和
然后我找到了一些关于 BIT 和 n 维情况的段树的信息,我认为我可以使用它们来解决这个问题。但是我很难实现工作变体(甚至在 1d 以上理解段树的工作原理)
也许有人可以帮助实施(或找到更好的解决方案并解释它)?
首先,我们需要一个有序的键/值数据结构,您可以插入、删除并及时O(log(n))
查找小于或等于您自己的上一个/最后一个值。 想想红黑树或树或跳过列表。
我将为该数据结构使用以下发明的符号。 我故意让它看起来不像任何真正的语言。
by_order.prev(key)
给出与最大键 <= 关联的 k-v 对key
。by_order.prev(key).k
将最大的密钥 <= 提供给key
。 这可以None
.by_order.prev(key).v
给出与最大键 <= 关联的值key
。by_order.next(key)
给出了与最小键>= 相关联的 k-v 对,以key
.k
和.v
表示他们以前所做的。by_order.add(key, value)
将添加一个k-v
对。by_order.del(key)
删除值为key
的k-v
对。
这个想法是这样的。 我们首先按x
排序,然后按y
排序,然后按z
排序。 第一个向量是最小的。 如果z
的值小于具有较低或相等y
的任何先前元素的最小值z
,则之后的每个向量都是最小的。 我们将使用by_order
数据结构来测试该条件。
假设我没有犯错,这里是伪代码:
sort(vectors) by x then y then z
Declare and initialize your empty ordered data structure by_order
// NOTE: by_order[val] will be the value of the largest key <= val
answer = [] // ie an empty list
answer.push(vectors[0])
by_order.add(vectors[0].y, by_order[vectors[0].z)
for v in vectors:
z_best = by_order.prev(v.y).v
if z_best is None or v.z < z_best:
answer.push(v) // Yay!
// Clear anything in by_order that we are an improvement on
while True:
pair = by_order.next(v)
if pair.v is not none and pair.k < v.z:
by_order.del(pair.v)
else:
break
// and now we add this one to by_order.
by_order.add(v.y, v.z)
排序所用的总时间为O(n log(n))
。
然后是n
向量中的每一个O(log(n))
查找以查看是否插入它,可能之后是O(1)
插入到答案中,O(log(n))
查找仍然跟随它的内容(别担心,我没有忘记被删除的那些),然后是O(log(n))
插入,然后是发现需要删除的O(log(n))
检查, 后跟O(log(n))
删除。
这是很多O(log(n))
术语,但总和仍然O(log(n))
.n
次。
结果是整个问题的O(n log(n))
算法。
我得到的想法:
struct Point {
int x;
int y;
int z;
};
bool operator < (const Point& lhs, const Point& rhs) {
return std::tie(lhs.x, lhs.y, lhs.z) < std::tie(rhs.x, rhs.y, rhs.z);
}
bool dominate(const Point& lhs, const Point& rhs) {
return lhs.x < rhs.x && lhs.y < rhs.y && lhs.z < rhs.z;
}
然后:
std::vector<Point> res;
const std::vector<Point> points = {...};
std::sort(points.begin(), points.end());
for (const auto& p : points) {
if (!std::any_of(res.begin(), res.end(), [](const auto& m) { return dominate(m, p);})) {
res.push_back(p);
}
}
return res.size();
复杂性仍然是最坏的情况n²
.(目前是max(n log n, res.size() * n)
)
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 递归函数计算序列中的平方和(并输出过程)
- (C++)分析树以计算返回错误值的简单算术表达式
- 我的字符计数代码计算错误.为什么
- 在计算中使用二的幂有多有利可图
- 如何计算文件中的"columns"数?
- 计算排序向量的向量中唯一值的计数
- 如何使用 std::累积在 C++ 中计算总和立方体
- 使用Qt C++计算类似Git的SHA1哈希
- OpenCV C++.快速计算混淆矩阵
- cpp二进制搜索问题,计算给定数组中输入元素的出现次数
- C++如何计算用户输入的数字中的偶数位数
- 如何计算数据类型的范围,例如int
- 类似枚举的计算常量
- 计算每个节点的树高,帮助我解释这个代码解决方案
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- 计算缩放多边形的比例,得到给定的多边形面积
- 在C++中如何在没有pow的情况下进行基础计算
- 计算平均值,不包括上次得分
- 计算"minimal"值