Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <deque>
- #include <functional>
- #include <iostream>
- #include <istream>
- #include <numeric>
- #include <unordered_map>
- #include <unordered_set>
- #include <utility>
- #include <vector>
- const int64_t 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_;
- };
- template<class T>
- using TypeIteratorRange = IteratorRange<typename std::vector<T>::const_iterator>;
- 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 n_vertices = 0);
- void AddEdge(int source, int destination);
- [[nodiscard]] size_t GetVerticesAmount() const;
- [[nodiscard]] TypeIteratorRange<Edge> OutgoingEdges(int source) const;
- private:
- std::vector<int> vertices_;
- std::vector<std::vector<Edge>> outgoing_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:
- FlowNetwork(int source, int sink, Graph graph,
- const std::vector<int> &capacity, const std::vector<int> &flow,
- const std::unordered_map<Edge, int> &edges);
- int GetSource() const;
- int GetSink() const;
- size_t GetVerticesAmount() const;
- TypeIteratorRange<Edge> OutgoingEdges(int source) const;
- int GetResidualCapacity(const Edge &edge) const;
- void ChangeFlow(const Edge &edge, int delta);
- auto ResidualNetworkView() const;
- private:
- int source_, sink_;
- Graph graph_;
- std::vector<int> capacity_, flow_;
- std::unordered_map<Edge, int> edges_;
- };
- class FlowNetworkBuilder {
- public:
- void constructGraph(int n_vertices);
- 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 Reset(int source, int sink);
- FlowNetwork Build();
- private:
- int source_, sink_;
- Graph graph;
- std::vector<int> capacity_, flow_;
- std::unordered_map<Edge, int> edges_;
- };
- class BfsVisitorLevel : public BfsVisitor {
- public:
- BfsVisitorLevel(int sink, std::vector<int> *level_);
- void ExamineEdge(const Edge &edge) override;
- bool Break() override;
- private:
- int sink_;
- std::vector<int> *level_;
- };
- class Dinic {
- public:
- explicit Dinic(FlowNetwork *flow_network)
- : flow_network_(flow_network), level_(flow_network->GetVerticesAmount()){}
- int MaxFlow();
- int CalculateAugmentingFlow(int vertex, int incoming_flow);
- private:
- 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);
- 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 &[who, whom] : trusts) {
- in_stream >> who >> whom;
- }
- return {golds, trusts};
- }
- 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.constructGraph(people_amount + 2);
- for (int vertex_id = 0; vertex_id < people_amount; ++vertex_id) {
- builder.AddEdge(source, vertex_id + 1, golds[vertex_id]);
- }
- for (auto &[source_id, destination_id] : trusts) {
- builder.AddEdge(source_id, destination_id, kInfinity);
- }
- for (int vertex_id = 0; vertex_id < people_amount; ++vertex_id) {
- builder.AddEdge(vertex_id + 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) {
- auto flow_network = BuildFlowNetworkFromGoldAndTrusts(golds, trusts, middle);
- return gold_sum == Dinic(&flow_network).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 n_vertices) {
- vertices_.resize(n_vertices);
- outgoing_edges_.resize(n_vertices);
- std::iota(vertices_.begin(), vertices_.end(), 0);
- }
- void Graph::AddEdge(int source, int destination) {
- outgoing_edges_[source].emplace_back(source, destination);
- }
- TypeIteratorRange<Edge> Graph::OutgoingEdges(int source) const {
- return {outgoing_edges_[source].begin(), outgoing_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::unordered_set<int> discovered{origin};
- 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 (discovered.count(destination) > 0) {
- continue;
- }
- discovered.insert(destination);
- 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_;
- }
- TypeIteratorRange<Edge> 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, [&](const Edge &edge) {
- return GetResidualCapacity(edge) > 0;
- });
- }
- FlowNetwork::FlowNetwork(int source, int sink, Graph graph, const std::vector<int> &capacity,
- const std::vector<int> &flow, const std::unordered_map<Edge, int> &edges)
- : source_(source), sink_(sink), graph_(std::move(graph)), capacity_(capacity), flow_(flow),
- edges_(edges) {}
- void FlowNetworkBuilder::constructGraph(int n_vertices) {
- graph = Graph(n_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);
- graph.AddEdge(source, destination);
- edges_[edge] = edges_.size();
- SetCapacity(edge, capacity);
- SetFlow(edge, 0);
- }
- void FlowNetworkBuilder::SetCapacity(const Edge &edge, int capacity) {
- std::size_t edge_id = edges_[edge];
- auto new_capacity_size = std::max(edge_id + 1, capacity_.size());
- capacity_.resize(new_capacity_size);
- capacity_[edge_id] = capacity;
- }
- void FlowNetworkBuilder::SetFlow(const Edge &edge, int flow) {
- std::size_t edge_id = edges_[edge];
- auto new_flow_size = std::max(edge_id + 1, flow_.size());
- flow_.resize(new_flow_size);
- flow_[edge_id] = flow;
- }
- void FlowNetworkBuilder::Reset(int source, int sink) {
- source_ = source;
- sink_ = sink;
- }
- FlowNetwork FlowNetworkBuilder::Build() {
- FlowNetwork flow_network(source_, sink_, std::move(graph), capacity_, flow_, edges_);
- return flow_network;
- }
- BfsVisitorLevel::BfsVisitorLevel(int sink, std::vector<int> *level_)
- : sink_(sink), level_(level_) {
- }
- void BfsVisitorLevel::ExamineEdge(const Edge &edge) {
- (*level_)[edge.destination] = edge.source;
- }
- bool BfsVisitorLevel::Break() {
- return (*level_)[sink_] != -1;
- }
- int Dinic::CalculateAugmentingFlow(int vertex, int incoming_flow) {
- if (vertex == flow_network_->GetSink()) {
- 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;
- while (true) {
- 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);
- } else {
- return answer;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment