Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <cstdio>
- #include <cstdlib>
- #include <deque>
- #include <functional>
- #include <iostream>
- #include <memory>
- #include <queue>
- #include <sstream>
- #include <unordered_set>
- #include <utility>
- #include <vector>
- template <class Iterator> class IteratorRange {
- public:
- IteratorRange(Iterator begin, Iterator end) : begin_(begin), end_(end) {}
- Iterator begin() const { return begin_; }
- Iterator end() const { return end_; }
- private:
- Iterator begin_, end_;
- };
- template <typename StlIterator> class Iterator {
- public:
- using ValueType = typename StlIterator::value_type;
- using Reference = typename StlIterator::reference;
- explicit Iterator(StlIterator current) : current_(current) {}
- Iterator &operator++() {
- ++current_;
- return *this;
- }
- bool operator==(const Iterator &rhs) const {
- return current_ == rhs.current_;
- }
- bool operator!=(const Iterator &rhs) const {
- return current_ != rhs.current_;
- }
- Reference operator*() const { return *current_; }
- private:
- StlIterator current_;
- };
- template <typename SourceIterator> class ProxyIterator {
- public:
- using ValueType = typename SourceIterator::ValueType;
- using Reference = typename SourceIterator::Reference;
- explicit ProxyIterator(SourceIterator &iterator) : iterator_(iterator) {}
- ProxyIterator &operator++() {
- ++iterator_;
- return *this;
- }
- bool operator==(const ProxyIterator &rhs) const {
- return iterator_ == rhs.iterator_;
- }
- bool operator!=(const ProxyIterator &rhs) const {
- return iterator_ != rhs.iterator_;
- }
- Reference operator*() const { return *iterator_; }
- private:
- SourceIterator &iterator_;
- };
- template <typename SourceIterator> class FilterIterator {
- public:
- using ValueType = typename SourceIterator::ValueType;
- using Reference = typename SourceIterator::Reference;
- using FilterFunc = std::function<bool(const Reference)>;
- FilterIterator(SourceIterator begin, SourceIterator end, FilterFunc func)
- : current_(begin), end_(end), filter_(func) {
- NextIfFilter();
- }
- FilterIterator(IteratorRange<SourceIterator> range, FilterFunc func)
- : current_(range.begin()), end_(range.end()), filter_(func) {
- NextIfFilter();
- }
- FilterIterator &operator++() {
- if (current_ != end_) {
- ++current_;
- NextIfFilter();
- }
- return *this;
- }
- bool operator==(const FilterIterator &rhs) {
- NextIfFilter();
- return current_ == rhs.current_;
- }
- bool operator!=(const FilterIterator &rhs) {
- return !(*this == rhs);
- }
- void NextIfFilter() {
- while (current_ != end_ && filter_(*current_)) {
- ++current_;
- }
- }
- Reference operator*() {
- NextIfFilter();
- return *current_;
- }
- private:
- SourceIterator current_;
- SourceIterator end_;
- FilterFunc filter_;
- };
- class Graph {
- public:
- struct Edge {
- int from;
- int to;
- int id;
- };
- using EdgeIterator = Iterator<std::vector<Edge>::const_iterator>;
- explicit Graph(int vertex_count) : outgoing_edges_(vertex_count) {}
- auto OutgoingEdges(int vertex) const {
- return IteratorRange<EdgeIterator>(
- EdgeIterator(outgoing_edges_[vertex].cbegin()),
- EdgeIterator(outgoing_edges_[vertex].cend()));
- }
- int VertexCount() const { return outgoing_edges_.size(); }
- const Edge &AddEdge(int from, int to) {
- outgoing_edges_[from].push_back(Edge{from, to, edge_count_++});
- return outgoing_edges_[from].back();
- }
- private:
- int edge_count_ = 0;
- std::vector<std::vector<Edge>> outgoing_edges_;
- };
- template <typename Graph> class LevelGraph {
- public:
- using Edge = typename Graph::Edge;
- using InnerEdgeIterator = FilterIterator<typename Graph::EdgeIterator>;
- using EdgeIterator = ProxyIterator<InnerEdgeIterator>;
- LevelGraph(const Graph &graph, const std::vector<int> &distances)
- : dist_(distances) {
- auto filter_func = [this](const Edge &edge) {
- return dist_[edge.to] != dist_[edge.from] + 1;
- };
- for (int vertex = 0; vertex < graph.VertexCount(); ++vertex) {
- outgoing_edges_.emplace_back(
- InnerEdgeIterator(graph.OutgoingEdges(vertex), filter_func),
- InnerEdgeIterator(graph.OutgoingEdges(vertex).end(),
- graph.OutgoingEdges(vertex).end(), filter_func));
- }
- }
- IteratorRange<EdgeIterator> OutgoingEdges(int vertex) {
- outgoing_edges_[vertex].first.NextIfFilter();
- return IteratorRange<EdgeIterator>(
- EdgeIterator(outgoing_edges_[vertex].first),
- EdgeIterator(outgoing_edges_[vertex].second));
- }
- int VertexCount() const { return outgoing_edges_.size(); }
- bool is_terminal_reachable(int vertex) { return dist_[vertex] != -1; }
- private:
- std::vector<int> dist_;
- std::vector<std::pair<InnerEdgeIterator, InnerEdgeIterator>> outgoing_edges_;
- };
- template <typename Graph, typename Visitor>
- void BreadthFirstSearch(int start_vertex, const Graph &graph, Visitor visitor) {
- std::unordered_set<int> used;
- std::queue<int> unvisited_vertices;
- unvisited_vertices.push(start_vertex);
- used.insert(start_vertex);
- visitor.DiscoverVertex(start_vertex);
- while (!unvisited_vertices.empty()) {
- auto from = unvisited_vertices.front();
- unvisited_vertices.pop();
- visitor.ExamineVertex(from);
- for (auto edge : graph.OutgoingEdges(from)) {
- if (!used.count(edge.to)) {
- visitor.DiscoverVertex(edge.to);
- unvisited_vertices.push(edge.to);
- used.insert(edge.to);
- visitor.ExamineEdge(edge);
- }
- }
- }
- }
- template <typename Graph, typename Visitor>
- void DepthFirstSearchImpl(int vertex, Graph &graph, Visitor &visitor,
- std::vector<bool> &used) {
- visitor.DiscoverVertex(vertex);
- if (visitor.CanStop()) {
- return;
- }
- used[vertex] = true;
- for (auto edge : graph.OutgoingEdges(vertex)) {
- if (!used[edge.to]) {
- visitor.ExamineEdge(edge);
- DepthFirstSearchImpl(edge.to, graph, visitor, used);
- if (visitor.CanStop()) {
- return;
- }
- visitor.FinishEdge(edge);
- }
- }
- visitor.FinishVertex(vertex);
- }
- template <typename Graph, typename Visitor>
- void DepthFirstSearch(int start_vertex, Graph &graph, Visitor visitor) {
- std::vector<bool> used(graph.VertexCount());
- DepthFirstSearchImpl(start_vertex, graph, visitor, used);
- }
- template <typename SourceGraph> class FilteredGraph {
- public:
- using EdgeIterator = FilterIterator<typename SourceGraph::EdgeIterator>;
- using FilterFunc = std::function<bool(const typename SourceGraph::Edge &)>;
- using Edge = typename SourceGraph::Edge;
- FilteredGraph(std::shared_ptr<const SourceGraph> source_graph,
- FilterFunc func)
- : source_graph_(source_graph), has_edge_(func) {}
- auto OutgoingEdges(int vertex) const {
- return IteratorRange<EdgeIterator>(
- EdgeIterator(source_graph_->OutgoingEdges(vertex), has_edge_),
- EdgeIterator(source_graph_->OutgoingEdges(vertex).end(),
- source_graph_->OutgoingEdges(vertex).end(), has_edge_)
- );
- }
- int VertexCount() const { return source_graph_->VertexCount(); }
- private:
- std::shared_ptr<const SourceGraph> source_graph_;
- FilterFunc has_edge_;
- };
- class FlowNetwork {
- public:
- using Edge = typename Graph::Edge;
- static const int INF = 1000000000;
- struct EdgeProperties {
- int flow;
- int cap;
- int opposite_index;
- };
- explicit FlowNetwork(int vertex_count)
- : network_(std::make_shared<Graph>(vertex_count)) {}
- Edge AddEdge(int from, int to, int cap) {
- auto &edge = network_->AddEdge(from, to);
- auto &back_edge = network_->AddEdge(to, from);
- edge_properties_.push_back({0, cap, back_edge.id});
- edge_properties_.push_back({0, 0, edge.id});
- return edge;
- }
- void IncFlow(const Edge &edge, int flow) {
- auto &edge_props = edge_properties_[edge.id];
- edge_properties_[edge.id].flow += flow;
- edge_properties_[edge_props.opposite_index].flow -= flow;
- }
- void SetCapacity(const Edge &edge, int capacity) {
- edge_properties_[edge.id].cap = capacity;
- }
- void ClearFlow() {
- for (auto &props : edge_properties_) {
- props.flow = 0;
- }
- }
- int ResidualCapacity(const Edge &edge) const {
- auto &props = edge_properties_[edge.id];
- return props.cap - props.flow;
- }
- bool IsInResidualNetwork(const Edge &edge) const {
- int res_cap = ResidualCapacity(edge);
- return res_cap > 0;
- }
- FilteredGraph<Graph> ResidualNetwork() const {
- auto filter_func = [this](const Edge &edge) {
- return !IsInResidualNetwork(edge);
- };
- return FilteredGraph<Graph>(network_, filter_func);
- }
- int64_t CalcFlowValue() {
- int64_t flow = 0;
- for (auto edge : network_->OutgoingEdges(0)) {
- auto &edge_props = edge_properties_[edge.id];
- flow += edge_props.flow;
- }
- return flow;
- }
- private:
- std::shared_ptr<Graph> network_;
- std::vector<EdgeProperties> edge_properties_;
- };
- template <typename VisitorState> class BreadthFirstSearchVisitor {
- public:
- explicit BreadthFirstSearchVisitor(VisitorState &state) : state_(state) {}
- void ExamineEdge(const typename VisitorState::Graph::Edge &edge) {
- state_.ExamineEdge(edge);
- }
- void ExamineVertex(int vertex) { state_.ExamineVertex(vertex); }
- void DiscoverVertex(int vertex) { state_.DiscoverVertex(vertex); }
- private:
- VisitorState &state_;
- };
- template <typename VisitorState>
- auto MakeBreadthFirstSearchVisitor(VisitorState &state) {
- return BreadthFirstSearchVisitor<VisitorState>(state);
- }
- template <typename SourceGraph> class CalcDistVisitorState {
- public:
- using Graph = SourceGraph;
- explicit CalcDistVisitorState(const Graph &graph)
- : dist_(graph.VertexCount(), -1) {}
- void ExamineEdge(const typename Graph::Edge &edge) {
- dist_[edge.to] = dist_[edge.from] + 1;
- }
- void DiscoverVertex(int vert) { dist_[vert] = 0; }
- void ExamineVertex(int vert) {}
- const std::vector<int> &GetDistances() const { return dist_; }
- private:
- std::vector<int> dist_;
- };
- template <typename Graph> LevelGraph<Graph> MakeLevelGraph(const Graph &graph) {
- CalcDistVisitorState<Graph> distance_visitor(graph);
- BreadthFirstSearch(0, graph, MakeBreadthFirstSearchVisitor(distance_visitor));
- LevelGraph<Graph> res(graph, distance_visitor.GetDistances());
- return res;
- }
- template <typename VisitorState> class DepthFirstSearchVisitor {
- public:
- explicit DepthFirstSearchVisitor(VisitorState &state) : state_(state) {}
- void ExamineEdge(const typename VisitorState::Graph::Edge &edge) {
- state_.ExamineEdge(edge);
- }
- void FinishEdge(const typename VisitorState::Graph::Edge &edge) {
- state_.FinishEdge(edge);
- }
- void FinishVertex(int vertex) { state_.FinishVertex(vertex); }
- void DiscoverVertex(int vertex) { state_.DiscoverVertex(vertex); }
- bool CanStop() { return state_.CanStop(); }
- private:
- VisitorState &state_;
- };
- template <typename VisitorState>
- auto MakeDepthFirstSearchVisitor(VisitorState &state) {
- return DepthFirstSearchVisitor<VisitorState>(state);
- }
- template <typename LevelGraph> class BlockFlowVisitorState {
- public:
- using Graph = LevelGraph;
- BlockFlowVisitorState(LevelGraph &level_graph, FlowNetwork &network,
- int terminal_vertex)
- : level_graph_(level_graph), network_(network),
- terminal_vertex_(terminal_vertex) {}
- void ExamineEdge(const typename Graph::Edge &edge) {
- cur_path_.push_back(edge);
- }
- void FinishEdge(const typename Graph::Edge &edge) { cur_path_.pop_back(); }
- const int INF = 1000000000;
- void DiscoverVertex(int vertex) {
- if (vertex == terminal_vertex_) {
- can_stop_ = true;
- int flow = INF;
- for (auto &edge : cur_path_) {
- flow = std::min(flow, network_.ResidualCapacity(edge));
- }
- for (auto &edge : cur_path_) {
- network_.IncFlow(edge, flow);
- }
- cur_path_.clear();
- }
- }
- void FinishVertex(int vertex) {}
- bool CanStop() const { return can_stop_; }
- bool ReachedTerminal() const { return CanStop(); }
- private:
- LevelGraph &level_graph_;
- FlowNetwork &network_;
- int terminal_vertex_;
- std::deque<typename Graph::Edge> cur_path_;
- bool can_stop_ = false;
- };
- int64_t FindMaxFlow(FlowNetwork &network) {
- bool is_terminal_reachable = true;
- while (is_terminal_reachable) {
- auto level_graph = MakeLevelGraph(network.ResidualNetwork());
- int terminal_vertex = level_graph.VertexCount() - 1;
- is_terminal_reachable = level_graph.is_terminal_reachable(terminal_vertex);
- if (is_terminal_reachable) {
- bool reached_terminal = true;
- while (reached_terminal) {
- BlockFlowVisitorState<decltype(level_graph)> block_flow_calculator(
- level_graph, network, terminal_vertex);
- DepthFirstSearch(0, level_graph,
- MakeDepthFirstSearchVisitor(block_flow_calculator));
- reached_terminal = block_flow_calculator.ReachedTerminal();
- }
- }
- }
- return network.CalcFlowValue();
- }
- // returns the minimal value (between begin and end), for which the predicate is
- // true
- template <typename Predicate>
- int FindMinimalTrue(int begin, int end, Predicate predicate) {
- while (begin != end) {
- int mid = (begin + end) / 2;
- if (predicate(mid)) {
- end = mid;
- } else {
- begin = mid + 1;
- }
- }
- return end;
- }
- void Read(std::vector<int> &starting_gold_bars_amount,
- std::vector<std::vector<int>> &trust_graph) {
- int people, trust_pairs;
- std::cin >> people >> trust_pairs;
- starting_gold_bars_amount.resize(people);
- for (auto &bars_amount : starting_gold_bars_amount) {
- std::cin >> bars_amount;
- }
- trust_graph.resize(people + 1);
- for (int i = 0; i < trust_pairs; ++i) {
- int from, to;
- std::cin >> from >> to;
- trust_graph[from].push_back(to);
- }
- }
- FlowNetwork
- BuildFlowNetwork(const std::vector<int> &starting_gold_bars_amount,
- const std::vector<std::vector<int>> &trust_graph,
- std::vector<typename FlowNetwork::Edge> &sink_edges,
- int &total_gold_bars) {
- int people = static_cast<int>(starting_gold_bars_amount.size());
- FlowNetwork network(people + 2);
- for (int i = 0; i < people; ++i) {
- network.AddEdge(0, i + 1, starting_gold_bars_amount[i]);
- sink_edges.push_back(network.AddEdge(i + 1, people + 1, 0));
- total_gold_bars += starting_gold_bars_amount[i];
- }
- for (int from = 1; from <= people; ++from) {
- for (auto to : trust_graph[from]) {
- network.AddEdge(from, to, FlowNetwork::INF);
- }
- }
- return network;
- }
- int FindMinimalGoldBarsAmount(
- std::vector<typename FlowNetwork::Edge> &sink_edges, FlowNetwork &network,
- int total_gold_bars) {
- auto check_enough_flow_with_capacity = [&network, &sink_edges,
- total_gold_bars](int cap) {
- network.ClearFlow();
- for (auto &edge : sink_edges) {
- network.SetCapacity(edge, cap);
- }
- int64_t flow = FindMaxFlow(network);
- return flow == total_gold_bars;
- };
- return FindMinimalTrue(0, total_gold_bars, check_enough_flow_with_capacity);
- }
- int main() {
- std::vector<int> starting_gold_bars_amount;
- std::vector<std::vector<int>> trust_graph;
- Read(starting_gold_bars_amount, trust_graph);
- int total_gold_bars = 0;
- std::vector<typename FlowNetwork::Edge> sink_edges;
- FlowNetwork network = BuildFlowNetwork(starting_gold_bars_amount, trust_graph,
- sink_edges, total_gold_bars);
- std::cout << FindMinimalGoldBarsAmount(sink_edges, network, total_gold_bars)
- << std::endl;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement