Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <deque>
- #include <functional>
- #include <iostream>
- #include <istream>
- #include <memory>
- #include <numeric>
- #include <unordered_map>
- #include <utility>
- #include <vector>
- const int kInfinity = 2000000000;
- /*
- Возвращает минимальное значение из полуинтервала [left; right) такое, что значение предиката истинно.
- predicate(left) должен быть равен false, predicate(right) должен быть равен true.
- Если по ошибке будет передан пустой полуинтервал, то будет возвращен right.
- */
- template<typename T, class Predicate>
- T BinarySearch(T left, T right, Predicate predicate);
- template<class Iterator>
- class IteratorRange {
- public:
- IteratorRange(Iterator begin, Iterator end);
- Iterator begin() const;// NOLINT
- Iterator end() const;// NOLINT
- private:
- Iterator begin_, end_;
- };
- struct Edge {
- int source, destination;
- Edge(int source, int destination);
- inline bool operator==(const Edge &other) const;
- };
- namespace std {
- template<>
- struct hash<Edge> {
- inline size_t operator()(const Edge &edge) const {
- std::hash<int> int_hasher;
- return int_hasher(edge.source) ^ int_hasher(edge.destination);
- }
- };
- }// namespace std
- class Graph {
- public:
- explicit Graph(int vertices);
- void AddEdge(int source, int destination);
- [[nodiscard]] size_t GetVerticesAmount() const;
- [[nodiscard]] IteratorRange<std::vector<Edge>::const_iterator> OutgoingEdges(int source) const;
- private:
- std::vector<int> vertices_;
- std::vector<std::vector<Edge>> edges_;
- };
- template<class Graph, class Visitor>
- void BFS(int origin, const Graph &graph, Visitor visitor);
- class BfsVisitor {
- public:
- virtual void ExamineEdge(const Edge &) = 0;
- virtual bool Break() = 0;
- virtual ~BfsVisitor() = default;
- };
- template<class Iterator, class Predicate>
- class FilterIterator {
- public:
- FilterIterator(Iterator first, Iterator last, Predicate predicate);
- auto operator*() const;
- auto operator++();
- auto operator!=(const FilterIterator &other) const;
- private:
- Iterator iter_, end_;
- Predicate predicate_;
- };
- template<class T, class Predicate>
- using FilterIteratorRange = IteratorRange < FilterIterator <
- typename std::vector<T>::const_iterator, Predicate>>;
- template<class Graph, class Predicate>
- class FilteredGraph {
- public:
- FilteredGraph(const Graph &graph, Predicate predicate);
- size_t GetVerticesAmount() const;
- [[nodiscard]] FilterIteratorRange<Edge, Predicate> OutgoingEdges(int source) const;
- private:
- const Graph &graph_;
- Predicate predicate_;
- };
- class FlowNetwork {
- public:
- explicit FlowNetwork(int vertices);
- int GetSource() const;
- int GetSink() const;
- size_t GetVerticesAmount() const;
- IteratorRange<std::vector<Edge>::const_iterator> OutgoingEdges(int source) const;
- int GetResidualCapacity(const Edge &edge) const;
- void ChangeFlow(const Edge &edge, int delta);
- auto ResidualNetworkView() const;
- private:
- int source_{}, sink_{};
- std::unique_ptr<Graph> graph_;
- std::vector<int> capacity_, flow_;
- std::unordered_map<Edge, int> edges_;
- friend class FlowNetworkBuilder;
- };
- class FlowNetworkBuilder {
- public:
- void SetVerticeAmount(int vertices);
- void SetEdgeAmount(int edges);
- void AddEdge(int source, int destination, int capacity);
- void AddEdgeInternal(int source, int destination, int capacity);
- void SetCapacity(const Edge &edge, int capacity);
- void SetFlow(const Edge &edge, int flow);
- void SetValue(const Edge &edge, int value, std::vector<int> *vector);
- void Reset(int source, int sink);
- std::unique_ptr<FlowNetwork> Build();
- private:
- std::unique_ptr<FlowNetwork> flow_network_ptr_;
- };
- class BfsVisitorLevel : public BfsVisitor {
- public:
- BfsVisitorLevel(int sink, std::vector<int> *level);
- bool Break();
- void ExamineEdge(const Edge &edge) override;
- private:
- int sink_;
- std::vector<int> *level_;
- };
- class Dinic {
- public:
- explicit Dinic(std::unique_ptr<FlowNetwork> flow_network);
- int MaxFlow();
- int CalculateAugmentingFlow(int vertex, int incoming_flow);
- private:
- std::unique_ptr<FlowNetwork> flow_network_;
- std::vector<int> level_;
- };
- std::pair<std::vector<int>, std::vector<std::pair<int, int>>>
- ReadGoldAndTrusts(std::istream &in_stream = std::cin);
- int CalculateOptimalDistribution(
- const std::vector<int> &golds, const std::vector<std::pair<int, int>> &trusts);
- std::unique_ptr<FlowNetwork> BuildFlowNetworkFromGoldAndTrusts(
- const std::vector<int> &golds, const std::vector<std::pair<int, int>> &trusts, int middle);
- void PrintOptimalDistribution(int distribution, std::ostream &out = std::cout);
- int main() {
- std::ios_base::sync_with_stdio(false);
- std::cin.tie(nullptr);
- auto [golds, trusts] = ReadGoldAndTrusts();
- PrintOptimalDistribution(CalculateOptimalDistribution(golds, trusts));
- return 0;
- }
- void PrintOptimalDistribution(int distribution, std::ostream &out) {
- out << distribution;
- }
- std::pair<std::vector<int>, std::vector<std::pair<int, int>>>
- ReadGoldAndTrusts(std::istream &in_stream) {
- int people_amount, trusts_amount;
- std::vector<int> golds;
- std::vector<std::pair<int, int>> trusts;
- in_stream >> people_amount >> trusts_amount;
- golds.resize(people_amount);
- for (auto &person : golds) {
- in_stream >> person;
- }
- trusts.resize(trusts_amount);
- for (auto &[from, to] : trusts) {
- in_stream >> from >> to;
- }
- return {golds, trusts};
- }
- std::unique_ptr<FlowNetwork> BuildFlowNetworkFromGoldAndTrusts(
- const std::vector<int> &golds, const std::vector<std::pair<int, int>> &trusts, int middle) {
- int people_amount = golds.size();
- int source = 0;
- int sink = people_amount + 1;
- FlowNetworkBuilder builder;
- builder.SetVerticeAmount(people_amount + 2);
- builder.SetEdgeAmount(2 * people_amount + trusts.size());
- for (int vertex = 0; vertex < people_amount; ++vertex) {
- builder.AddEdge(source, vertex + 1, golds[vertex]);
- }
- for (auto &[from, to] : trusts) {
- builder.AddEdge(from, to, kInfinity);
- }
- for (int vertex = 0; vertex < people_amount; ++vertex) {
- builder.AddEdge(vertex + 1, sink, middle);
- }
- builder.Reset(source, sink);
- return builder.Build();
- }
- int CalculateOptimalDistribution(const std::vector<int> &golds,
- const std::vector<std::pair<int, int>> &trusts) {
- int gold_sum = std::accumulate(golds.begin(), golds.end(), 0);
- int left = 0;
- int right = *std::max_element(golds.begin(), golds.end());
- return BinarySearch(left, right, [&](int middle) {
- return gold_sum ==
- Dinic(std::move(BuildFlowNetworkFromGoldAndTrusts(golds, trusts, middle))).MaxFlow();
- });
- }
- template<class Iterator>
- IteratorRange<Iterator>::IteratorRange(Iterator begin, Iterator end) : begin_(begin), end_(end) {
- }
- template<class Iterator>
- Iterator IteratorRange<Iterator>::begin() const {// NOLINT
- return begin_;
- }
- template<class Iterator>
- Iterator IteratorRange<Iterator>::end() const {// NOLINT
- return end_;
- }
- template<typename T, class Predicate>
- T BinarySearch(T left, T right, Predicate predicate) {
- while (right - left > 1) {
- T middle = (right + left) / 2;
- if (predicate(middle)) {
- right = middle;
- } else {
- left = middle;
- }
- }
- return right;
- }
- Edge::Edge(int source, int destination) : source(source), destination(destination) {
- }
- bool Edge::operator==(const Edge &other) const {
- return source == other.source && destination == other.destination;
- }
- Graph::Graph(int vertices) {
- vertices_.resize(vertices);
- edges_.resize(vertices);
- std::iota(vertices_.begin(), vertices_.end(), 0);
- }
- void Graph::AddEdge(int source, int destination) {
- edges_[source].emplace_back(source, destination);
- }
- IteratorRange<std::vector<Edge>::const_iterator> Graph::OutgoingEdges(int source) const {
- return {edges_[source].begin(), edges_[source].end()};
- }
- size_t Graph::GetVerticesAmount() const {
- return vertices_.size();
- }
- template<class Graph, class Visitor>
- void BFS(int origin, const Graph &graph, Visitor visitor) {
- std::deque<int> processing_vertices{origin};
- std::vector<bool> is_discovered(graph.GetVerticesAmount());
- is_discovered[origin] = true;
- while (!processing_vertices.empty()) {
- auto current = processing_vertices.front();
- processing_vertices.pop_front();
- for (const auto &edge : graph.OutgoingEdges(current)) {
- auto destination = edge.destination;
- if (is_discovered[destination]) {
- continue;
- }
- is_discovered[destination] = true;
- processing_vertices.push_back(destination);
- visitor.ExamineEdge(edge);
- if (visitor.Break()) {
- return;
- }
- }
- }
- }
- template<class Iterator, class Predicate>
- FilterIterator<Iterator, Predicate>::FilterIterator(Iterator first, Iterator last,
- Predicate predicate)
- : iter_(first), end_(last), predicate_(predicate) {
- while (iter_ != end_ && !predicate_(*iter_)) {
- ++iter_;
- }
- }
- template<class Iterator, class Predicate>
- auto FilterIterator<Iterator, Predicate>::operator*() const {
- return *iter_;
- }
- template<class Iterator, class Predicate>
- auto FilterIterator<Iterator, Predicate>::operator++() {
- do {
- ++iter_;
- } while (iter_ != end_ && !predicate_(*iter_));
- }
- template<class Iterator, class Predicate>
- auto FilterIterator<Iterator, Predicate>::operator!=(const FilterIterator &other) const {
- return iter_ != other.iter_;
- }
- template<class Graph, class Predicate>
- size_t FilteredGraph<Graph, Predicate>::GetVerticesAmount() const {
- return graph_.GetVerticesAmount();
- }
- template<class Graph, class Predicate>
- FilterIteratorRange<Edge, Predicate>
- FilteredGraph<Graph, Predicate>::OutgoingEdges(int source) const {
- auto iterator_range = graph_.OutgoingEdges(source);
- auto filter_begin = FilterIterator(iterator_range.begin(), iterator_range.end(), predicate_);
- auto filter_end = FilterIterator(iterator_range.end(), iterator_range.end(), predicate_);
- return {filter_begin, filter_end};
- }
- template<class Graph, class Predicate>
- FilteredGraph<Graph, Predicate>::FilteredGraph(const Graph &graph, Predicate predicate)
- : graph_(graph), predicate_(predicate) {
- }
- int FlowNetwork::GetSource() const {
- return source_;
- }
- int FlowNetwork::GetSink() const {
- return sink_;
- }
- IteratorRange<std::vector<Edge>::const_iterator> FlowNetwork::OutgoingEdges(int source) const {
- return graph_->OutgoingEdges(source);
- }
- void FlowNetwork::ChangeFlow(const Edge &edge, int delta) {
- flow_.at(edges_.at(edge)) += delta;
- flow_.at(edges_.at(edge) ^ 1) -= delta;
- }
- int FlowNetwork::GetResidualCapacity(const Edge &edge) const {
- return capacity_.at(edges_.at(edge)) - flow_.at(edges_.at(edge));
- }
- size_t FlowNetwork::GetVerticesAmount() const {
- return graph_->GetVerticesAmount();
- }
- auto FlowNetwork::ResidualNetworkView() const {
- return FilteredGraph(*this, [this](const Edge &edge) {
- return GetResidualCapacity(edge) > 0;
- });
- }
- FlowNetwork::FlowNetwork(int vertices) : graph_(std::make_unique<Graph>(vertices)) {
- }
- void FlowNetworkBuilder::SetVerticeAmount(int vertices) {
- flow_network_ptr_ = std::make_unique<FlowNetwork>(vertices);
- }
- void FlowNetworkBuilder::AddEdge(int source, int destination, int capacity) {
- AddEdgeInternal(source, destination, capacity);
- AddEdgeInternal(destination, source, 0);
- }
- void FlowNetworkBuilder::AddEdgeInternal(int source, int destination, int capacity) {
- Edge edge(source, destination);
- flow_network_ptr_->graph_->AddEdge(source, destination);
- flow_network_ptr_->edges_[edge] = flow_network_ptr_->edges_.size();
- SetCapacity(edge, capacity);
- SetFlow(edge, 0);
- }
- void FlowNetworkBuilder::SetCapacity(const Edge &edge, int capacity) {
- SetValue(edge, capacity, &flow_network_ptr_->capacity_);
- }
- void FlowNetworkBuilder::SetFlow(const Edge &edge, int flow) {
- SetValue(edge, flow, &flow_network_ptr_->flow_);
- }
- void FlowNetworkBuilder::SetValue(const Edge &edge, int value, std::vector<int> *vector) {
- std::size_t edge_id = flow_network_ptr_->edges_[edge];
- (*vector)[edge_id] = value;
- }
- void FlowNetworkBuilder::Reset(int source, int sink) {
- flow_network_ptr_->source_ = source;
- flow_network_ptr_->sink_ = sink;
- }
- std::unique_ptr<FlowNetwork> FlowNetworkBuilder::Build() {
- return std::move(flow_network_ptr_);
- }
- void FlowNetworkBuilder::SetEdgeAmount(int edges) {
- flow_network_ptr_->flow_.resize(2 * edges);
- flow_network_ptr_->capacity_.resize(2 * edges);
- }
- BfsVisitorLevel::BfsVisitorLevel(int sink, std::vector<int> *level)
- : sink_(sink), level_(level) {
- }
- bool BfsVisitorLevel::Break() {
- return (*level_)[sink_] != -1;
- }
- void BfsVisitorLevel::ExamineEdge(const Edge &edge) {
- (*level_)[edge.destination] = edge.source;
- }
- int Dinic::CalculateAugmentingFlow(int vertex, int incoming_flow) {
- if (vertex == flow_network_->GetSink() || incoming_flow == 0) {
- return incoming_flow;
- }
- int outgoing_flow = 0;
- for (auto edge : flow_network_->OutgoingEdges(vertex)) {
- int destination = edge.destination;
- if (level_[destination] == vertex) {
- auto new_incoming = std::min(incoming_flow, flow_network_->GetResidualCapacity(edge));
- auto min_flow = CalculateAugmentingFlow(destination, new_incoming);
- if (min_flow > 0) {
- flow_network_->ChangeFlow(edge, min_flow);
- outgoing_flow += min_flow;
- incoming_flow -= min_flow;
- if (incoming_flow == 0) {
- break;
- }
- }
- }
- }
- return outgoing_flow;
- }
- int Dinic::MaxFlow() {
- int answer = 0;
- do {
- level_.assign(level_.size(), -1);
- auto visitor = BfsVisitorLevel(flow_network_->GetSink(), &level_);
- BFS(flow_network_->GetSource(), flow_network_->ResidualNetworkView(), visitor);
- if (level_[flow_network_->GetSink()] != -1) {
- answer += CalculateAugmentingFlow(flow_network_->GetSource(), kInfinity);
- }
- } while (level_[flow_network_->GetSink()] != -1);
- return answer;
- }
- Dinic::Dinic(std::unique_ptr<FlowNetwork> flow_network)
- : flow_network_(std::move(flow_network)), level_(flow_network_->GetVerticesAmount()) {}
Advertisement
Add Comment
Please, Sign In to add comment