数"最小"值

时间:2018-03-01 15:45:11

标签: c++ algorithm data-structures segment-tree binary-indexed-tree

问题:

我输入了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;
}

并构建基于数组(例如min-heap),允许查找最小值(使用<)并计算它们(我认为我只是"重新创建"一个不好的变体按照这种方式堆排序)。在我尝试失败之后,我尝试了Fenwick树(二进制索引树)来执行相同的任务。

但是我知道我的方法不正确(不是ok类和<重载),而且在1d中转换任务的想法并不好。

然后我发现了一些有关BIT& amp;的信息。 n维案例的分段树,我认为我可以用它们来解决这个问题。但是我很难实现工作变体(甚至在1d以上了解分段树的工作原理)

也许有人可以帮助实施(或找到更好的解决方案并解释它)?

2 个答案:

答案 0 :(得分:1)

我得到的想法:

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();

复杂性仍处于最坏情况。 (目前是max(n log n, res.size() * n)

答案 1 :(得分:1)

首先,我们需要一个有序的键/值数据结构,您可以插入,删除并找到小于或等于您自己的时间O(log(n))的prev / last值。想想红黑树或btree或跳过列表。

我将使用以下发明的表示法来表示该数据结构。我故意让它看起来不像任何真正的语言。

by_order.prev(key)给出与最大键&lt; = key相关联的k-v对。 by_order.prev(key).k提供最大的密钥&lt; = key。这可以是Noneby_order.prev(key).v给出与最大键&lt; = key相关联的值。 by_order.next(key)将与最小键&gt; = key相关联的k-v对与.k.v相关联,这意味着他们之前所做的事情。 by_order.add(key, value)添加k-v对。 by_order.del(key)移除了值为k-v的{​​{1}}对。

这个想法是这样的。我们首先按key然后x然后y排序。第一个向量是最小的。如果z的值小于z的最低值,那么之后的每个向量都是最小的,对于任何具有低于或等于z的先前元素。我们将使用y数据结构来测试该条件。

假设我没有犯错,这里是伪代码:

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))次。{/ p>

结果是针对整个问题的n算法。