Poklon

poklon.cpp
poklon.py

_179
//
_179
// Created by Gaelan McMillan on 2022-09-10.
_179
//
_179
_179
#ifndef MORE_GENERIC_PATIENCE_H
_179
#define MORE_GENERIC_PATIENCE_H
_179
_179
/* * * * * * *\
_179
* Objective:
_179
* Sort a std::container of elements to find the longest chain,
_179
* given a comparator describing some partial order.
_179
*
_179
* Return value could be a few things. Some problems only need to know the number of elements
_179
* in the longest chain. (The Longest Monotone Subsequence problem)
_179
*
_179
* Some variations ask for the subsequence itself. In this case, having patience return a lazy-convertible struct
_179
* (essentially a wrapper around the subsequence tail) could be ideal.
_179
*
_179
* Let's explore how we want the API to behave.
_179
* In the case of "Poklon":
_179
*
_179
* ```
_179
* struct interval { int low, high; };
_179
* std::vector<interval> intervals {...};
_179
* sort(intervals.begin(), intervals.end(), preprocess);
_179
* auto LIS = patience(intervals.begin(), intervals.end(), comparator);
_179
* for (auto& element : LIS)
_179
* {
_179
* std::cout << element.low << ' ' << element.high << '\n';
_179
* }
_179
* ```
_179
*
_179
* In the case of "Russian Doll Envelopes"
_179
*
_179
* ```
_179
* sort(envelopes.begin(), envelopes.end(), preprocess);
_179
* auto LIS = patience(envelopes.begin(), envelopes.end(), comparator);
_179
* return LIS.size();
_179
* ```
_179
*
_179
* Currently passing longest-monotone-subsequence tests.
_179
* Non-monotone tests are more subtle.
_179
* */
_179
#include <vector>
_179
#include <algorithm>
_179
#include <numeric>
_179
#include <iostream>
_179
_179
template<class InputIterator, class Comparator, class BiPred>
_179
auto __patience (InputIterator begin, InputIterator end, Comparator pre, BiPred pred)
_179
{
_179
using T = typename std::iterator_traits<InputIterator>::value_type;
_179
_179
if constexpr(not std::is_same_v<Comparator, std::nullptr_t>)
_179
std::sort(begin, end, pre);
_179
_179
struct node
_179
{
_179
T item;
_179
node* next;
_179
node() = default;
_179
node(T t, node* p) : item(t), next(p) {}
_179
};
_179
_179
auto node_pred = [&pred] (node* a, node* b)
_179
{
_179
return pred(a->item, b->item);
_179
};
_179
_179
const auto dist = std::distance(begin, end);
_179
node* nodes = new node[dist];
_179
_179
std::vector<node*> piles;
_179
_179
for (; begin != end; ++begin)
_179
{
_179
node* wrapped = new (nodes++) node(*begin, nullptr);
_179
if (piles.empty())
_179
{
_179
piles.push_back(wrapped);
_179
continue;
_179
}
_179
_179
auto lb = std::lower_bound(piles.begin(), piles.end(), wrapped, node_pred);
_179
_179
if (lb == piles.begin()) // new first pile
_179
{
_179
*lb = wrapped;
_179
}
_179
else if (lb == piles.end())
_179
{
_179
wrapped->next = piles.back();
_179
piles.push_back(wrapped);
_179
}
_179
else
_179
{
_179
wrapped->next = *(lb-1);
_179
*lb = wrapped;
_179
}
_179
_179
}
_179
_179
std::vector<T> seq;
_179
node* cur = piles.back();
_179
_179
while (cur != nullptr)
_179
{
_179
seq.push_back(cur->item);
_179
cur = cur->next;
_179
}
_179
_179
std::reverse(seq.begin(), seq.end());
_179
return seq;
_179
}
_179
_179
template <class II>
_179
auto patience(II begin, II end)
_179
{
_179
using T = typename std::iterator_traits<II>::value_type;
_179
return __patience(begin, end, nullptr, std::less<T>());
_179
}
_179
_179
template <class II, class Comparator, class BiPred>
_179
auto patience(II begin, II end, Comparator pre, BiPred pred)
_179
{
_179
return __patience(begin, end, pre, pred);
_179
}
_179
_179
/*
_179
* Maybe returning a convertible struct would be a nice API.
_179
*
_179
* auto p = make_patience(vec.begin(), vec.end())
_179
* .with_preprocess() // argument can be a comparator — std::less<> by default
_179
* .non_monotone()
_179
* */
_179
#endif //MORE_GENERIC_PATIENCE_H
_179
_179
_179
using namespace std;
_179
_179
int main()
_179
{
_179
struct interval
_179
{
_179
int low;
_179
int high;
_179
};
_179
_179
int n;
_179
cin >> n;
_179
vector<interval> intervals (n);
_179
for (interval& i : intervals)
_179
{
_179
cin >> i.low >> i.high;
_179
}
_179
_179
auto preprocess = [](const interval& a, const interval& b) {
_179
if (a.low == b.low)
_179
return a.high > b.high;
_179
return a.low < b.low;
_179
};
_179
_179
auto pred = [](const interval& a, const interval& b) {
_179
return a.high >= b.high;
_179
};
_179
_179
auto LIS = patience (
_179
intervals.begin(),
_179
intervals.end(),
_179
preprocess,
_179
pred
_179
);
_179
_179
cout << LIS.size() << '\n';
_179
for (auto e : LIS)
_179
std::cout << e.low << ' ' << e.high << '\n';
_179
_179
return 0;
_179
}

If you found this solution helpful, consider leaving a star!